alf*_*lfC 5 c++ boost pointers boost-interprocess boost-container
我有一个类似指针的结构,代替指针.与指针的区别在于它具有(也是特殊的)分配器可以用来释放内存的额外信息.
这种类似指针的结构适用于所有基本用途.我可以分配和释放内存,dereferrence,increment ->
等.
现在我想使用这个指针由类似STL的容器管理.早期,我意识到STL向量基本上不能处理非原始指针.
T*
太硬编码了,标准基本上排除了任何不是指针的东西.
受Boost.Interprocess的启发' offset_ptr<T>
我决定使用Boost.Container vector
,它是非常可定制的,原则上可以管理任何东西,传递给它的分配器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));
Run Code Online (Sandbox Code Playgroud)
后面是后面的
[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.
Run Code Online (Sandbox Code Playgroud)
两条线都绝对杀死了使用任何不是的东西的可能性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);
Run Code Online (Sandbox Code Playgroud)
是否有一种变通方法或使用Boost容器向量来处理非原始指针的替代方法?
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);
}
};
Run Code Online (Sandbox Code Playgroud)
完整的工作代码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});
}
Run Code Online (Sandbox Code Playgroud)
我调查了一些事情。
\n\nTL;DR 似乎是:支持非原始指针,但在某些操作中它们需要从原始指针进行隐式转换。这是否是设计使然,我不知道,但这似乎并不与设计目标相矛盾。
\n\n事实上,这与分配器支持的历史非常相似:STL 容器支持自定义分配器,但不支持有状态分配器(即非默认可构造分配器类型)。
\n\n首先我尝试了一些分配器版本:
\n\nusing version = boost::container::version_0; // seems unsupported, really\nusing version = boost::container::version_1;\nusing version = boost::container::version_2; // does different operations\n
Run Code Online (Sandbox Code Playgroud)\n\n但它没有(决定性的)影响。也许文档有线索。
\n\n之后我查看了具体的错误。看着引用的行/错误,我突然意识到原始指针可能是一个意外。看看这些的输出:
\n\nstd::cout << boost::container::container_detail::impl::version<allocator<int> >::value << "\\n";\n\narray_ptr<int> p;\nauto rawp = boost::container::container_detail::to_raw_pointer(p);\nstd::cout << typeid(rawp).name() << "\\n";\n\nstd::cout << typeid(p).name() << "\\n";\nstd::cout << typeid(p + 5).name() << "\\n";\nstd::cout << typeid(p - 5).name() << "\\n";\n
Run Code Online (Sandbox Code Playgroud)\n\n显示类似\xc2\xb9
\n\n1\nint*\narray_ptr<int>\nint*\nint*\n
Run Code Online (Sandbox Code Playgroud)\n\n\xc2\xb9 在以下的帮助下进行美化c++filt -t
这导致我定义指针算术:
\n\ntemplate <typename T, typename N>\narray_ptr<T> operator+(array_ptr<T> const& p, N n) { return array_ptr<T>(p.p+n, p.i); }\n\ntemplate <typename T>\narray_ptr<T>& operator++(array_ptr<T>& p) { return ++p.p, p; }\n\ntemplate <typename T>\narray_ptr<T> operator++(array_ptr<T>& p, int) { auto q = p.p++; return array_ptr<T>(q, p.i); }\n\ntemplate <typename T, typename N>\narray_ptr<T> operator-(array_ptr<T> const& p, N n) { return array_ptr<T>(p.p-n, p.i); }\n\ntemplate <typename T>\nptrdiff_t operator-(array_ptr<T> const& a, array_ptr<T> const& b) { return a.p - b.p; }\n
Run Code Online (Sandbox Code Playgroud)\n\n现在输出变成
\n\n1\nint*\narray_ptr<int>\narray_ptr<int>\narray_ptr<int>\n
Run Code Online (Sandbox Code Playgroud)\n\n更多用例可以使用这些定义成功编译。假设里面的“注释”数据array_pointer
在增量后有效,它不应该丢失任何分配器信息
尽管如此,有些东西仍然无法编译。具体来说,在某些情况下,分配器的pointer
类型是从原始指针构造回来的。这会失败,因为没有合适的“默认”转换构造函数。如果您声明带有可选数据值的构造函数,则所有内容都会编译,但您可能会认为这会丢失信息,因为存在一条来自
array_pointer<T> p;\n auto* rawp = to_raw_pointer(p);\n array_pointer<T> clone(rawp); // oops lost the extra info in p\n
Run Code Online (Sandbox Code Playgroud)\n\n请注意,正如您显然意识到的那样(从注释的运算符来看),添加默认构造函数参数消除了对算术运算的需要(预递增除外)。
\n\n但是,添加它们可以确保减少有损转换路径的发生,这对您的用例可能很重要。
\n\n#if COMPILATION_INSTRUCTIONS\nclang++ -std=c++14 -Wall -Wfatal-errors $0 -o $0x.x && $0x.x $@ && rm -f $0x.x; exit\n#endif\n\n#define DEFAULT_DATA = 0\n#define DEFINE_ARITHMETIC_OPERATIONS\n\n#include <iostream>\n#include <boost/container/vector.hpp>\n#include <typeinfo>\n\ntemplate<typename T>\nstruct array_ptr {\n T* p;\n int i; //some additional information\n\n T& operator*() const { return *p; }\n T* operator->() const { return p; }\n\n operator T*() const { return p; }\n\n array_ptr(){}\n //array_ptr(std::nullptr_t) : p(nullptr), i(0){}\n array_ptr(T* ptr, int _i DEFAULT_DATA) : p(ptr), i(_i){}\n\n};\n\ntemplate<>\nstruct array_ptr<void> {\n using T = void;\n T* p;\n int i; //some additional information\n\n// T& operator*() const { return *p; }\n T* operator->() const { return p; }\n\n operator T*() const { return p; }\n template<class T>\n operator array_ptr<T>() const{return array_ptr<T>((T*)p, i);}\n// array_ptr& operator++(){++p; return *this;}\n array_ptr(){}\n array_ptr(std::nullptr_t) : p(nullptr){}\n array_ptr(T* ptr, int _i DEFAULT_DATA) : p(ptr), i(_i){}\n template<class Other>\n array_ptr(array_ptr<Other> other) : p(other.p), i(other.i){}\n};\n\ntemplate<>\nstruct array_ptr<void const> {\n using T = void const;\n T* p;\n int i; //some additional information\n\n// T& operator*() const { return *p; }\n T* operator->() const { return p; }\n\n operator T*() const { return p; }\n// array_ptr& operator++(){++p; return *this;}\n// template<class Other> array_ptr(array_ptr<Other> const& other) : p(other.p), i(other.i){}\n array_ptr(){}\n array_ptr(std::nullptr_t) : p(nullptr){}\n array_ptr(T* ptr, int _i DEFAULT_DATA) : p(ptr), i(_i){}\n template<class Other>\n array_ptr(array_ptr<Other> other) : p(other.p), i(other.i){}\n};\n\nstruct some_managed_shared_memory {\n array_ptr<void> allocate(size_t n) { return array_ptr<void>(::malloc(n), 99); }\n void deallocate(array_ptr<void> ptr) { if (ptr) ::free(ptr.p); }\n};\n\ntemplate<typename T>\nstruct allocator{\n using version = boost::container::version_1;\n\n using value_type = T;\n using pointer = array_ptr<T>; // simulates T*\n using const_pointer = array_ptr<T const>; // simulates T const*\n using void_pointer = array_ptr<void>; // simulates void*\n using const_void_pointer = array_ptr<void const>; // simulates void const*\n\n some_managed_shared_memory& msm_;\n allocator(some_managed_shared_memory& msm) : msm_(msm){}\n array_ptr<T> allocate(size_t n){\n auto ret = msm_.allocate(n*sizeof(T));\n return static_cast<array_ptr<T>>(ret);\n }\n void deallocate(array_ptr<T> ptr, std::size_t = 0){\n msm_.deallocate(ptr);\n }\n};\n\n#ifdef DEFINE_ARITHMETIC_OPERATIONS\n template <typename T, typename N>\n array_ptr<T> operator+(array_ptr<T> const& p, N n) { return array_ptr<T>(p.p+n, p.i); }\n\n template <typename T>\n array_ptr<T>& operator++(array_ptr<T>& p) { return ++p.p, p; }\n\n template <typename T>\n array_ptr<T> operator++(array_ptr<T>& p, int) { auto q = p.p++; return array_ptr<T>(q, p.i); }\n\n template <typename T, typename N>\n array_ptr<T> operator-(array_ptr<T> const& p, N n) { return array_ptr<T>(p.p-n, p.i); }\n\n template <typename T>\n ptrdiff_t operator-(array_ptr<T> const& a, array_ptr<T> const& b) { return a.p - b.p; }\n#endif\n\n\nint main() {\n std::cout << boost::container::container_detail::impl::version<allocator<int> >::value << "\\n";\n\n if (1) { // some diagnostics\n array_ptr<int> p;\n auto rawp = boost::container::container_detail::to_raw_pointer(p);\n std::cout << typeid(rawp).name() << "\\n";\n\n std::cout << typeid(p).name() << "\\n";\n std::cout << typeid(p + 5).name() << "\\n";\n std::cout << typeid(p - 5).name() << "\\n";\n }\n\n some_managed_shared_memory realm;\n boost::container::vector<int, allocator<int> > v(10, realm);\n assert( v[4] == 0 );\n v[4] = 1;\n assert( v[4] == 1 );\n for(std::size_t i = 0; i != v.size(); ++i) std::cout << v[i] << std::endl;\n\n // these compile:\n v.push_back(12);\n v.resize(100);\n v.assign({1,2,3,4,5});\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n印刷
\n\n1\nPi\n9array_ptrIiE\n9array_ptrIiE\n9array_ptrIiE\n0\n0\n0\n0\n1\n0\n0\n0\n0\n0\n
Run Code Online (Sandbox Code Playgroud)\n
归档时间: |
|
查看次数: |
222 次 |
最近记录: |