【发布时间】:2012-06-01 14:00:47
【问题描述】:
struct Foo
{
Foo(int i)
{
ptr = new int(i);
}
~Foo()
{
delete ptr;
}
int* ptr;
};
int main()
{
{
Foo a(8);
Foo b(7);
a = b;
}
//Do other stuff
}
如果我理解正确的话,编译器会自动为Foo创建一个赋值运算符成员函数。但是,这只是将ptr 的值放入b 并将其放入a。 a 分配的内存原本似乎丢失了。我可以在分配之前拨打a.~Foo();,但我听说你应该很少需要显式调用析构函数。因此,假设我为Foo 编写了一个赋值运算符,它在将右值分配给左值之前删除了左操作数的int 指针。像这样:
Foo& operator=(const Foo& other)
{
//To handle self-assignment:
if (this != &other) {
delete this->ptr;
this->ptr = other.ptr;
}
return *this;
}
但是如果我这样做,那么当Foo a 和Foo b 超出范围时,它们的析构函数不会运行,两次删除同一个指针(因为它们现在都指向同一个东西)?
编辑:
如果我正确理解 Anders K,这是正确的做法:
Foo& operator=(const Foo& other)
{
//To handle self-assignment:
if (this != &other) {
delete this->ptr;
//Clones the int
this->ptr = new int(*other.ptr);
}
return *this;
}
现在,a 克隆了b 指向的int,并设置了自己的指针指向它。也许在这种情况下,delete 和new 不是必需的,因为它只涉及ints,但是如果数据成员不是int* 而是Bar* 或诸如此类,则可能需要重新分配.
编辑 2: 最好的解决方案似乎是copy-and-swap idiom。
【问题讨论】:
-
我不知道答案。您是否考虑过使用 valgrind 或其他工具对其进行测试?
-
这不会编译,因为您尝试使用默认构造函数,但没有。
-
@BenjaminLindley 对此感到抱歉,已编辑。
-
您已经正确回答了自己的问题。在第一种情况下,您对内存泄漏是正确的。在第二种情况下,您对双重删除是正确的(这是未定义的行为)。
-
赋值运算符可以而且应该使用更安全、更高效的复制和交换习语来实现。
标签: c++ memory-leaks assignment-operator