¿Puede el vector Boost Container administrar la memoria a través de punteros no sin procesar?

Tengo una estructura similar a un puntero que va en lugar de un puntero. La diferencia con un puntero es que tiene información adicional que el asignador (también especial) puede usar para desasignar la memoria.

Esta estructura tipo puntero funciona bien para todos los usos básicos. Puedo asignar y desasignar memoria, desreferencia, incremento,->etc.

Ahora quiero usar estos punteros para que sean administrados por un contenedor similar a STL. Al principio, me di cuenta de que el vector STL básicamente no puede manejar punteros no sin procesar.T* está demasiado codificado y el estándar básicamente descarta cualquier cosa que no sea un puntero.

Inspirado por Boost.Interprocess 'offset_ptr<T> Decidí usar Boost.Containervector, que es muy personalizable y, en principio, puede administrar cualquier cosa, el asignador pasó alboost::container::vector puede manejar cualquier cosa que sea como un puntero.

Ahora la claseboost::container::vector<T, myallocator_with_special_pointer<T>> puede hacer cualquier cosa ... exceptoresize()!!

Mirando el código enboost/container/vector.hpp parece que el proceso de cambio de tamaño (que es básicamente una asignación, seguido de una copia (o movimiento) y desasignación) implica punteros en bruto.

La línea ofensiva es:

  [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));

Que luego es seguido por

  [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.

Ambas líneas eliminan absolutamente la posibilidad de usar cualquier cosa que no searaw_pointer. Incluso si tengo un operador de conversión a un puntero sin formato, se perderá otra información sobre el puntero especial.

Parece bastante tonto que este pequeño detalle prohíba el uso de punteros no crudos. Dado todo el esfuerzo para que el contenedor sea general (por ejemplo, definir elpointer typedef), por qué esta parte del código usaT* solo por cambiar el tamaño?

En otras palabras, ¿por qué Boost Container no usa esta línea?

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

¿Existe una solución alternativa o una forma alternativa de usar el vector Boost Container para manejar punteros no sin procesar?

Boost.Container dice en su página de manualhttp://www.boost.org/doc/libs/1_64_0/doc/html/container/history_and_reasons.html#container.history_and_reasons.Why_boost_container

Boost.Container es producto de un largo esfuerzo de desarrollo que comenzó en 2004 con la biblioteca experimental Shmem, que fue pionera en el uso de contenedores estándar en la memoria compartida. Shmem incluyó el código modificado del contenedor SGI STL ajustado para soportarno crudo allocator::pointer tipos y asignadores con estado. Una vez revisado, Shmem fue aceptado como Boost. Interprocess y esta biblioteca continuó refinando y mejorando esos contenedores.

La implementación actual (en el contexto del cambio de tamaño) va en contra de este objetivo de diseño.

Hice una pregunta menos específica aquí, sobre otros rasgos de los asignadores:¿Todavía es posible personalizar el tipo de "referencia" del vector STL?

Como referencia, el asignador que especifica el puntero especial (que se propaga al contenedor) es algo como esto,

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);
    }
};

Código de trabajo completohttp://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});
}

Respuestas a la pregunta(1)

Su respuesta a la pregunta