struct A {
~A () {}
};
struct S {
S() : i(0) { }
~S() {}
int i;
// This fails:
//
// A a[];
A a[0];
};
int main()
{
struct A aaa;
return 0;
}
请注意,如果将零大小的数组替换为灵活数组成员 (FAM)
A a[];
,则会出现错误:error: unknown array size in delete
。
我从here找到了这个例子。
我在自定义动态扩展容器类中遇到了这个问题。
我的问题:如何解决?零大小的数组是否是有效的替换并且工作良好? 例如,使用
operator new
为类的实例分配内存并使用 operator delete
释放内存,如下所示:
size_t totalSize = sizeof(MyContainer) + capacity * sizeof(MyElement);
void* memory = operator new(totalSize);
MyContainer* container = new (memory) MyContainer();
// ...
operator delete((void*)container);
标准 C++ 中不存在灵活数组成员。您的特定编译器可能(或可能不)支持它们作为语言扩展。如果是这样,它们与其他 C++ 功能的使用可能会受到严重限制。
用
A a[0];
替换灵活的数组成员并不会使其变得更好。在标准 C++ 中也不能将数组声明为零大小。同样,如果可以编译,这将是您的特定编译器的某种语言扩展。而且,与适当的灵活数组成员相比,它们甚至也不是标准 C,这使得语义更加不清楚。
delete
不可能与具有非平凡析构函数的类型的灵活数组成员一起使用。 delete
需要知道数组的大小,因为它需要调用数组每个元素的非平凡析构函数。但它无法知道这个大小。
您需要自己使用
operator new
/operator new[]
分配内存,在通过placement-new或std::construct_at
获得的内存中创建对象,并通过显式析构函数调用或调用std::destroy_at
手动销毁您创建的每个元素。然后您需要使用 operator delete
/operator delete[]
手动释放内存。
不需要灵活的数组成员来实现你想要的。用户不应使用
MyContainer*
来引用您的容器实例。相反, MyContainer
应该由用户按值使用,并且 MyContainer
应该是保存指向动态分配内存的指针的类类型。 i
成员是否保存在 MyContainer
中或在其所保存的指针分配开始时,由您决定。
看看标准库实现是如何实现的
std::vector
。您本质上是在尝试实现同样的事情,但可能具有有限的功能集。此外,这些实现并不在分配开始时存储大小,而是存储在容器对象本身中,但这是一个细微的差别。在 C++ 中正确实现这样的容器并非易事,需要对对象模型有充分的了解。