我有一个类List
,它自动分配内存来存储项目列表。
它有一个析构函数来释放这个内存:
List::~List()
{
free(memory);
}
这意味着,如果我创建一个new
列表,我可以使用delete
来调用析构函数并释放内存。
一旦变量超出范围,也会调用析构函数,这几乎总是我想要的。 e.g:
int func()
{
List list;
list.push(...);
...
return 47;
}
但是,如果我想返回该列表该怎么办?
List func()
{
List list;
return list;
}
我正好复制列表,因为它是按值返回的,并且没有太多要复制的数据(只有几个整数和一个指针)。
但是,列表分配并具有指针的内存包含大量数据。
由于我正在返回列表,因此正在将列表与指向此数据的指针一起复制。
由于列表现在超出了范围,因此调用析构函数,释放指向该数据的指针,即使副本也有指针。
如何阻止调用此析构函数?
1)通过创建一个复制构造函数可能有一个解决方案,但是,我不想这样做,因为那个指针上的所有数据都可能不得不被复制,这是浪费时间,暂时需要加倍要分配的内存。
2)我知道我可以创建一个指针List* list
并返回它,但我想避免为可能的情况下为该列表分配新内存的必要性,并且还想避免为指针浪费更多内存(8个字节或者其他)。
提前致谢,
大卫。
答案 0 :(得分:6)
假设您正在使用C ++ 11或更高版本,您只需创建一个move constructor,将旧列表留空。
为了避免类似的问题,您还需要删除复制构造函数,或者实际编写它以便可以复制您的类(不要担心;在返回值的情况下编译器将使用移动构造函数或return-value optimization)。
通过将指针存储为unique_ptr
可以大大简化这一过程,这将有助于确保您不会出错,并且意味着您不需要显式编写副本或移动构造函数。
如果你坚持使用预C ++ 11,那么你不能这样做,至少不会没有很小的存储空间惩罚。你需要使用像boost::shared_ptr
这样的引用计数指针(一个版本被添加到带有C ++ 11的标准库中,但听起来你宁愿只移动语义),它只会释放内存,当它是最后一个引用该内存的时候。这使得复制,创建和销毁列表的速度稍慢(因为它需要检查/更新引用计数器),并且需要一些空间来存储计数,但与实际复制列表内容相比,这些成本相对较小。
请注意,在这种情况下,两个副本始终指向实际上相同的列表。如果更新一个“副本”,另一个也会更新。这通常不是您的类的用户在C ++中期望的行为。