在大项目上复制赋值运算符内存泄漏
Copy assignment operator memory leak, on big project
过去几个月我一直在做一个大项目。现在我终于完成了那个项目。但是在我的复制赋值运算符中我有内存泄漏。 Valgrind 显示泄漏的是 data_ 的原始值。
这是我的复制赋值运算符代码。
Value& Value::operator=(const Value& r)
{
data_ = copy(r.data_);
delete data_;
return *this;
}
谁能帮我解决这个问题?我真的很感激。
我相信你想写这个:
delete data_; //here it makes sense: delete the current value
data_ = copy(r.data_); //copy now
不是这个:
data_ = copy(r.data_); //LEAK, as data_ is pointing to current value
delete data_; //here you're deleting the copied one
确保 data_
始终指向有效内存——否则有条件地删除它。
这没有意义:
data_ = copy(r.data_);
delete data_;
因为如果 data_
指向已分配的内存,而您 将其覆盖 为
data_ = copy(r.data_);
和然后删除新复制的区域,你有内存泄漏(你不能再引用你原来分配的内存)。
删除刚刚复制的内存的一大好处:如果你真的使用了 _data
指针,你会得到未定义的行为。
你可能打算写
template <typename T>
Value<T>& Value<T>::operator=(const Value<T>& r)
{
delete data_; // Free this object's memory
data_ = copy(r.data_); // And now get a copy (hopefully a deep one) of the new memory
return *this;
}
一个小警告:上面的代码即使修复了 也没有强大的异常保证:如果内存复制由于任何原因失败,您可能会得到一个不一致的对象(因为 data_
已被删除)。
问题是data_
刚复制就删掉了!
data_ = copy(r.data_);
delete data_; <<< PROBLEM
最好的解决方案可能是使用复制和交换惯用语 (What is the copy-and-swap idiom?)。
template <typename T>
Value<T>& Value<T>::operator=(const Value<T> rhs) // NOTE: pass by value
{
swap(data_, rhs.data_); // either std::swap or a custom swap,
// hard to say without knowing the type of data_
return *this;
}
另一种选择,对 OP 代码的直接增强,可能如下所示。
template <typename T>
Value<T>& Value<T>::operator=(const Value<T>& r)
{
// 1) Allocate new data. If, for some reason, the allocation throws,
// the original data_ stays intact. This offers better
// exception safety.
... new_data = ...;
// 2) Copy r.data to new_data (note: deep copy desired)
new_data = copy(r.data_);
// 3) Destroy original data_
delete data_;
// 4) Point data_ to new_data
data_ = new_data;
return *this;
}
过去几个月我一直在做一个大项目。现在我终于完成了那个项目。但是在我的复制赋值运算符中我有内存泄漏。 Valgrind 显示泄漏的是 data_ 的原始值。
这是我的复制赋值运算符代码。
Value& Value::operator=(const Value& r)
{
data_ = copy(r.data_);
delete data_;
return *this;
}
谁能帮我解决这个问题?我真的很感激。
我相信你想写这个:
delete data_; //here it makes sense: delete the current value
data_ = copy(r.data_); //copy now
不是这个:
data_ = copy(r.data_); //LEAK, as data_ is pointing to current value
delete data_; //here you're deleting the copied one
确保 data_
始终指向有效内存——否则有条件地删除它。
这没有意义:
data_ = copy(r.data_);
delete data_;
因为如果 data_
指向已分配的内存,而您 将其覆盖 为
data_ = copy(r.data_);
和然后删除新复制的区域,你有内存泄漏(你不能再引用你原来分配的内存)。
删除刚刚复制的内存的一大好处:如果你真的使用了 _data
指针,你会得到未定义的行为。
你可能打算写
template <typename T>
Value<T>& Value<T>::operator=(const Value<T>& r)
{
delete data_; // Free this object's memory
data_ = copy(r.data_); // And now get a copy (hopefully a deep one) of the new memory
return *this;
}
一个小警告:上面的代码即使修复了 也没有强大的异常保证:如果内存复制由于任何原因失败,您可能会得到一个不一致的对象(因为 data_
已被删除)。
问题是data_
刚复制就删掉了!
data_ = copy(r.data_);
delete data_; <<< PROBLEM
最好的解决方案可能是使用复制和交换惯用语 (What is the copy-and-swap idiom?)。
template <typename T>
Value<T>& Value<T>::operator=(const Value<T> rhs) // NOTE: pass by value
{
swap(data_, rhs.data_); // either std::swap or a custom swap,
// hard to say without knowing the type of data_
return *this;
}
另一种选择,对 OP 代码的直接增强,可能如下所示。
template <typename T>
Value<T>& Value<T>::operator=(const Value<T>& r)
{
// 1) Allocate new data. If, for some reason, the allocation throws,
// the original data_ stays intact. This offers better
// exception safety.
... new_data = ...;
// 2) Copy r.data to new_data (note: deep copy desired)
new_data = copy(r.data_);
// 3) Destroy original data_
delete data_;
// 4) Point data_ to new_data
data_ = new_data;
return *this;
}