O vetor Boost Container pode gerenciar a memória através de ponteiros não brutos?

Eu tenho uma estrutura semelhante a um ponteiro que entra no lugar de um ponteiro. A diferença com um ponteiro é que ele possui informações extras que o alocador (também especial) pode usar para desalocar a memória.

Essa estrutura semelhante a ponteiro funciona bem para todos os usos básicos. Posso alocar e desalocar memória, desreferencia, incremento,->, etc.

Agora eu quero usar esses ponteiros para serem gerenciados por um contêiner do tipo STL. Desde o início, percebi que o vetor STL basicamente não pode lidar com ponteiros não brutos.T* é muito codificado e o padrão basicamente exclui qualquer coisa que não seja um ponteiro.

Inspirado pelo Boost.Interprocess 'offset_ptr<T> Decidi usar o Boost.Containervector, que é muito personalizável e, em princípio, pode gerenciar qualquer coisa, o alocador passado para oboost::container::vector pode lidar com qualquer coisa semelhante a ponteiro.

Agora a aulaboost::container::vector<T, myallocator_with_special_pointer<T>> pode fazer qualquer coisa ... excetoresize()!!

Olhando o código emboost/container/vector.hpp parece que o processo de redimensionamento (que é basicamente a alocação, seguido de uma cópia (ou movimentação) e desalocação) envolve indicadores brutos.

A linha ofensiva é:

  [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 é posteriormente 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 as linhas eliminam absolutamente a possibilidade de usar qualquer coisa que não seja umraw_pointer. Mesmo se eu tiver um operador de conversão em um ponteiro bruto, outras informações sobre o ponteiro especial serão perdidas.

Parece muito bobo que esse pequeno detalhe proíba o uso de ponteiros não brutos. Dado todo o esforço para que o contêiner seja geral (por exemplo, definindo opointer typedef), por que essa parte do código usaT* apenas para redimensionar?

Em outras palavras, por que o Boost Container não usa essa linha

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

Existe uma solução alternativa ou uma maneira alternativa de usar o vetor Boost Container para manipular ponteiros não brutos?

Boost.Container diz em sua 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

O Boost.Container é um produto de um longo esforço de desenvolvimento iniciado em 2004 com a biblioteca experimental Shmem, pioneira no uso de contêineres padrão na memória compartilhada. A Shmem incluiu o código de contêiner SGI STL modificado ajustado para oferecer suportenão cru allocator::pointer tipos e alocadores stateful. Uma vez revisado, o Shmem foi aceito como Boost.Interprocess e essa biblioteca continuou a refinar e aprimorar esses contêineres.

A implementação atual (no contexto de redimensionamento) vai contra esse objetivo de design.

Fiz uma pergunta menos específica aqui, sobre outras características dos alocadores:Ainda é possível personalizar o tipo de "referência" do vetor STL?

Para referência, o alocador que especifica o ponteiro especial (que é propagado para o contêiner) é algo como isto,

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

questionAnswers(1)

yourAnswerToTheQuestion