Gen*_*yev 2 c++ arrays memory-management
基本思想是创建一个可变大小的数组,在构造时固定,并在单个分配单元中创建另一个类,以减少开销并提高效率。分配一个缓冲区来容纳数组,并使用另一个对象和新的放置来构造它们。为了访问数组和另一个对象的元素,使用了指针算术和reinterpret_cast。这似乎有效(至少在 gcc 中),但我对标准(5.2.10 Reinterpret Cast)的阅读告诉我这是一种未定义的行为。那是对的吗?如果是这样,有没有办法在没有UB的情况下实现这个设计?
完整的可编译示例在这里: http: //ideone.com/C9CCa8
// a buffer contains array of A followed by B, laid out like this
// | A[N - 1] ... A[0] | B |
class A
{
size_t index;
//...
// using reinterpret_cast to get to B object
const B* getB() const
{
return reinterpret_cast<const B*>(this + index + 1);
}
};
class B
{
size_t a_count;
//...
virtual ~B() {}
// using reinterpret_cast to get to the array member
const A* getA(size_t i) const
{
return reinterpret_cast<const A*>(this) - i - 1;
}
};
// using placement new to construct all objects in raw memory
B* make_record(size_t a_count)
{
char* buf = new char[a_count*sizeof(A) + sizeof(B)];
for(auto i = 0; i < a_count; ++i)
{
new(buf) A(a_count - i - 1);
buf += sizeof(A);
}
return new(buf) B(a_count);
}
Run Code Online (Sandbox Code Playgroud)
当使用新的放置时,您需要确保目标内存与您的数据类型正确对齐,否则这是未定义的行为。在 A 数组之后,不能保证 buf 的对齐对于 B 类型的对象来说是正确的。您对 reinterpret_cast 的使用也是未定义的行为。
未定义的行为并不意味着它不起作用。它可能适用于特定的编译器,以及一组特定的类类型和指针偏移量等。但是您不能将此代码放入任意符合标准的编译器中并保证它能够工作。
使用这些黑客行为强烈表明您没有正确设计解决方案。