quuxplusone.github.io/draft/fancy-pointers.html

я есть структура, похожая на указатель, которая идет вместо указателя. Разница с указателем заключается в том, что он имеет дополнительную информацию, которую (также специальный) распределитель может использовать для освобождения памяти.

Эта структура, подобная указателю, хорошо работает для всех основных целей. Я могу выделить и освободить память, разыменование, приращение,->, так далее.

Теперь я хочу использовать эти указатели для управления STL-подобным контейнером. Ранее я понял, что вектор STL в принципе не может обрабатывать неочищенные указатели.T* слишком жестко запрограммирован, и стандарт в основном исключает все, что не является указателем.

Вдохновленный Boost.Interprocess 'offset_ptr<T> Я решил использовать Boost.Containervector, который очень настраиваемый и в принципе может управлять всем, распределитель передаетсяboost::container::vector может обрабатывать все, что похоже на указатель.

Сейчас классboost::container::vector<T, myallocator_with_special_pointer<T>> могу сделать что угодно ... кромеresize()!!

Глядя на код вboost/container/vector.hpp кажется, что процесс изменения размера (который в основном состоит из выделения и последующего копирования (или перемещения) и освобождения) включает в себя необработанные указатели.

Оскорбительная строка:

  [line 2729:] T * const new_buf = container_detail::to_raw_pointer
     (allocator_traits_type::allocate(this->m_holder.alloc(), new_cap, this->m_holder.m_start));

Который позже сопровождается

  [line 3022:] this->m_holder.start(new_start);  // new_start is the same as new_buf above. 
  // member ::start(pointer&) will need to convert a raw pointer to the pointer typedef.

Обе строки абсолютно убивают возможность использования всего, что не являетсяraw_pointer, Даже если у меня есть оператор преобразования в необработанный указатель, другая информация о специальном указателе будет потеряна.

Кажется довольно глупым, что эта маленькая деталь запрещает использование не сырых указателей. Учитывая все усилия, чтобы контейнер был общим (например, определениеpointer typedef), почему эта часть кода используетT* только для изменения размера?

Другими словами, почему Boost Container не использует эту строку вместо

  [alternative] pointer const new_buf = 
     allocator_traits_type::allocate(this->m_holder.alloc(), new_cap, this->m_holder.m_start);

Есть ли обходной путь или альтернативный способ использовать вектор Boost Container для обработки неочищенных указателей?

Boost.Container говорит на своей странице руководстваhttp://www.boost.org/doc/libs/1_64_0/doc/html/container/history_and_reasons.html#container.history_and_reasons.Why_boost_container

Boost.Container - это продукт длительной разработки, которая началась в 2004 году с экспериментальной библиотеки Shmem, которая впервые использовала стандартные контейнеры в разделяемой памяти. Shmem включил модифицированный код контейнера SGI STL, настроенный для поддержкине-сырец allocator::pointer типы и распределители состояний. После проверки Shmem был принят как Boost.Interprocess, и эта библиотека продолжала дорабатывать и улучшать эти контейнеры.

Текущая реализация (в контексте изменения размера) идет вразрез с этой целью проектирования.

Я задал здесь менее конкретный вопрос о других особенностях распределителей:Можно ли по-прежнему настраивать «эталонный» тип вектора STL?

Для справки распределитель, который указывает специальный указатель (который распространяется на контейнер), выглядит примерно так:

template<class T>
struct allocator{
    using value_type = T;
    using pointer = array_ptr<T>; // simulates T*
    using const_pointer = array_ptr<T const>; // simulates T const*
    using void_pointer = array_ptr<void>; // simulates void*
    using const_void_pointer = array_ptr<void const>; // simulates void const*
    some_managed_shared_memory& msm_;
    allocator(some_managed_shared_memory& msm) : msm_(msm){}
    array_ptr<T> allocate(mpi3::size_t n){
        auto ret = msm_.allocate(n*sizeof(T));
        return static_cast<array_ptr<T>>(ret);
    }
    void deallocate(array_ptr<T> ptr, mpi3::size_t = 0){
        msm_.deallocate(ptr);
    }
};

Полный рабочий кодhttp://coliru.stacked-crooked.com/a/f43b6096f9464cbf

#include<iostream>
#include <boost/container/vector.hpp>

template<typename T>
struct array_ptr;

template<>
struct array_ptr<void> {
    using T = void;
    T* p;
    int i; //some additional information

//    T& operator*() const { return *p; }
    T* operator->() const { return p; }

//    operator T*() const { return p; }
    template<class TT>
    operator array_ptr<TT>() const{return array_ptr<TT>((TT*)p, i);}
    operator bool() const{return p;}
    array_ptr(){}
    array_ptr(std::nullptr_t) : p(nullptr){}
    array_ptr(T* ptr, int _i) : p(ptr), i(_i){}
    template<class Other>
    array_ptr(array_ptr<Other> other) : p(other.p), i(other.i){}
};

template<>
struct array_ptr<void const> {
    using T = void const;
    T* p;
    int i; //some additional information

//    T& operator*() const { return *p; }
    T* operator->() const { return p; }

    operator T*() const { return p; }
    array_ptr(){}
    array_ptr(std::nullptr_t) : p(nullptr){}
    array_ptr(T* ptr, int _i) : p(ptr), i(_i){}
    template<class Other>
    array_ptr(array_ptr<Other> other) : p(other.p), i(other.i){}
};

template<typename T>
struct array_ptr {
    T* p;
    int i; //some additional information

    T& operator*() const { return *p; }
    T* operator->() const { return p; }
    T& operator[](std::size_t n) const{
        assert(i == 99);
        return *(p + n);
    }
    bool operator==(array_ptr const& other) const{return p == other.p and i == other.i;}
    bool operator!=(array_ptr const& other) const{return not((*this)==other);}

//    operator T*() const { return p; }
    array_ptr& operator++(){++p; return *this;}
    array_ptr& operator+=(std::ptrdiff_t n){p+=n; return *this;}
    array_ptr& operator-=(std::ptrdiff_t n){p-=n; return *this;}
    array_ptr operator+(std::size_t n) const{array_ptr ret(*this); ret+=n; return ret;}
    std::ptrdiff_t operator-(array_ptr const& other) const{return p - other.p;}
    array_ptr(){}
    array_ptr(std::nullptr_t) : p(nullptr), i(0){}

    operator bool() const{return p;}

    array_ptr(T* ptr, int _i) : p(ptr), i(_i){}
    array_ptr(T* ptr) : p(ptr), i(0){}
    array_ptr(int) : p(nullptr), i(0){}
    array_ptr(array_ptr<void> const& other) : p(static_cast<T*>(other.p)), i(other.i){}
};

struct some_managed_shared_memory {
    array_ptr<void> allocate(size_t n) { return array_ptr<void>(::malloc(n), 99); }
    void  deallocate(array_ptr<void> ptr) { if (ptr) ::free(ptr.p); }
};

template<typename T>
struct allocator{
    using value_type = T;
    using pointer = array_ptr<T>; // simulates T*
    using const_pointer = array_ptr<T const>; // simulates T const*
    using void_pointer = array_ptr<void>; // simulates void*
    using const_void_pointer = array_ptr<void const>; // simulates void const*

    some_managed_shared_memory& msm_;
    allocator(some_managed_shared_memory& msm) : msm_(msm){}
    array_ptr<T> allocate(size_t n){
        auto ret = msm_.allocate(n*sizeof(T));
        return static_cast<array_ptr<T>>(ret);
    }
    void deallocate(array_ptr<T> ptr, std::size_t = 0){
        msm_.deallocate(ptr);
    }
};

int main() {
    some_managed_shared_memory realm;
    boost::container::vector<int, allocator<int> > v(10, realm);
    assert( v[4] == 0 );
    v[4] = 1;
    assert( v[4] == 1 );
    for(std::size_t i = 0; i != v.size(); ++i) std::cout << v[i] << std::endl;
    for(auto it = v.begin(); it != v.end(); ++it) std::cout << *it << std::endl;

    // none of these compile:
    v.push_back(8);
    assert(v.size() == 11);
    v.resize(100);
    std::cout << v[89] << std::endl; // will fail an assert because the allocator information is lost
    //v.assign({1,2,3,4,5});
}

Ответы на вопрос(0)

Ваш ответ на вопрос