使用具有灵活数组成员 (FAM) 和非平凡析构函数的类时,如何解决“删除时未知数组大小”错误?

问题描述 投票:0回答:1
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++ memory-management dynamic flexible-array-member
1个回答
0
投票

标准 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++ 中正确实现这样的容器并非易事,需要对对象模型有充分的了解。

© www.soinside.com 2019 - 2024. All rights reserved.