我目前的理解是C++11 移动和复制赋值运算符都应该调用 delete 以防止内存泄漏,但 C++11 移动和复制构造函数不应该。
如果我的理解是正确的,构造函数不需要调用delete
,但是我不确定为什么。考虑以下示例:
class my_class
{
my_class(int num_data) : my_data{new double[num_data]}, my_data_length{num_data}
{
}
// This class manages a resource
double *my_data;
int my_data_length;
}
// Big 4 go here - see wikipedia example below.
my_class a(10);
my_class b(10);
my_class c(10);
a = b; // Need to delete old storage contained in a before reallocating
a(c); // For some reason we don't need to delete the old storage here? I find this puzzling
查看此维基百科文章中的示例代码,我很清楚:
Move Constructor 不会因为资源被转移而泄漏。任何由未到期的类指向的已分配数据都将转移到即将到期的类,并由即将到期的类的析构函数删除。
但是,我对 Copy Constructor 是否泄漏感到困惑。
移动赋值运算符可能不会泄漏,因为它只是交换指针。
我再次对复制分配运算符感到困惑。我不确定为什么需要使用临时对象?我的猜测是在此函数结束时超出范围时所拥有的资源并被销毁
tmp
?other
(除了tmp
它的资源与类中的指针交换了this
吗?)
为方便起见,下面提供了代码:
#include <cstring>
#include <iostream>
class Foo
{
public:
/** Default constructor */
Foo() :
data (new char[14])
{
std::strcpy(data, "Hello, World!");
}
/** Copy constructor */
Foo (const Foo& other) :
data (new char[std::strlen (other.data) + 1])
{
std::strcpy(data, other.data);
}
/** Move constructor */
Foo (Foo&& other) noexcept : /* noexcept needed to enable optimizations in containers */
data(other.data)
{
other.data = nullptr;
}
/** Destructor */
~Foo() noexcept /* explicitly specified destructors should be annotated noexcept as best-practice */
{
delete[] data;
}
/** Copy assignment operator */
Foo& operator= (const Foo& other)
{
Foo tmp(other); // re-use copy-constructor
*this = std::move(tmp); // re-use move-assignment
return *this;
}
/** Move assignment operator */
Foo& operator= (Foo&& other) noexcept
{
// simplified move-constructor that also protects against move-to-self.
std::swap(data, other.data); // repeat for all elements
return *this;
}
private:
friend std::ostream& operator<< (std::ostream& os, const Foo& foo)
{
os << foo.data;
return os;
}
char* data;
};
int main()
{
const Foo foo;
std::cout << foo << std::endl;
return 0;
}
我想这暗示了为什么设置(未初始化/未分配)悬空指针很重要nullptr
,因为这将防止在删除析构函数时出现内存错误?
我认为这是因为资源通过移动构造函数传输的情况,但是过期对象接收到一个从未分配过的悬空指针——我们不希望随后调用析构函数和delete
指针——除非我们确保它指向nullptr
(无操作)。
谁能澄清我提出的一些观点?