template<class T, class D>
struct var_array_at_end {
var_array_at_end( std::size_t N ) {
::new( (void*)data() ) std::aligned_storage_t<sizeof(T)*N, alignof(T)>;
for (std::size_t i = 0; i < N; ++i) {
::new( (void*)( data()+sizeof(T)*i) ) ) T();
}
}
char* data() { return reinterpret_cast<char*>(this)+sizeof(D); }
char const* data() const { return reinterpret_cast<char*>(this)+sizeof(D); }
T* ptr(std::size_t i = 0) { return reinterpret_cast<T*>( data()+sizeof(T)*i ); }
T const* ptr(std::size_t i = 0) const { return reinterpret_cast<T*>( data()+sizeof(T)*i ); }
T& operator[](std::size_t n) {
return *ptr(n);
}
T const& operator[](std::size_t n) const {
return *ptr(n);
}
};
struct MyData:
var_array_at_end<int, MyData>
{
private:
explicit MyData( int count ):
var_array_at_end<int, MyData>( count>0?(unsigned)count:0 ),
noOfItems(count)
{}
struct cleanup {
void operator()(MyData* ptr) {
char* buff = reinterpret_cast<char*>(ptr);
ptr->~MyData();
delete[] buff;
}
};
public:
using up = std::unique_ptr<MyData*, cleanup>;
static up create( int count ) {
if (count < 0) count = 0;
std::unique_ptr<char> buff = std::make_unique<char[]>( sizeof(MyData)+sizeof(int)*count );
auto* ptr = ::new( (void*)buff.get() ) MyData( count );
(void)buff.release();
return up( ptr, {} );
}
int noOfItems;
};
MyData * getData(int size)
{
return MyData::create(size).release(); // dangerous, unmanaged memory
}
我相信这是符合标准的,假设您的实现没有在普通类型的数组(如char)上添加填充。我不知道它的任何实现。
我没想到
MyData
只包含简单的旧数据;您可以填充
std::vector
和上面的一样。我可以用这个假设简化几行。
这不仅仅是一点痛苦。
auto foo = MyData::create(100)
创建唯一的ptr到
MyDATA
有100个缓冲区
int
在后面。
(*foo)[77]
访问缓冲区的第77个元素。
由于标准中存在缺陷,在
MyDATA
而是一个包含100个不同的
int
相邻内存位置中的对象。这两件事之间有一些令人恼火的区别;幼稚的指针算术可以保证在数组中工作,但不能在压缩的相邻数组之间工作。
int
在缓冲器中。我不知道有哪个编译器会强制执行这种差异。