返回堆栈变量时停止调用析构函数

Stop destructor from calling when returning stack variable

我有一个 class List 自动分配内存来存储项目列表。

它有一个释放内存的析构函数:

List::~List()
{
    free(memory);
}

这意味着,如果我创建一个 new 列表,我可以使用 delete 调用析构函数并释放内存。

一旦变量超出范围,析构函数也将被调用,这几乎总是我想要的。例如:

int func()
{
    List list;
    list.push(...);
    ...
    return 47;
}

但是,如果我想 return 该列表怎么办?

List func()
{
    List list;
    return list;
}

我对正在复制的列表没问题,因为它是按值 return 编辑的,并且没有太多数据要复制(只有几个整数和一个指针)。

但是,列表分配并有指针指向的内存包含大量数据。

由于我正在 returning 列表,因此正在复制列表以及指向此数据的指针。

由于列表现在超出范围,因此调用析构函数,释放指向该数据的指针,即使副本也有指针。

如何防止调用此析构函数?


1) 创建复制构造函数可能是一个解决方案,但是,我不想这样做,因为那样可能必须复制该指针上的所有数据,这会暂时浪费时间需要分配双倍的内存。

2) 我知道我可以只创建一个指针 List* list 和 return ,但我想尽可能避免为该列表分配新内存的必要性,也想避免为指针浪费更多内存(8 字节或其他)。


提前致谢,

大卫.

假设您使用的是 C++11 或更高版本,您只需创建一个 move constructor 将旧列表留空。

为了避免类似的问题,你还需要删除复制构造函数,或者实际写成这样你的class可以被复制(不用担心; 在大多数情况下,包括您担心从函数返回的情况,编译器将使用移动构造函数或 get rid of the copy/move entirely,尤其是在 C++17 之后)。

通过将指针存储为 unique_ptr,这大大简化了这将有助于确保您不会出错,并且意味着您不需要显式编写复制或移动构造函数。


如果你停留在 C++11 之前的版本,你不能这样做,至少在没有小的存储-space 惩罚的情况下不能这样做。您需要使用像 boost::shared_ptr 这样的引用计数指针(C++11 将一个版本添加到标准库中,但听起来您更愿意只移动语义),这只会释放当它是最后一个引用该内存的内存时。这使得复制、创建和销毁列表的速度稍慢(因为它需要 check/update 引用计数器),并且需要一些 space 来存储计数,但这些成本与实际上是在复制列表的内容。

请注意,在这种情况下,两个副本始终指向实际上是同一个列表。如果您更新一个“副本”,另一个也会更新。这通常不是您的 class 用户在 C++ 中所期望的行为。