【发布时间】:2011-10-11 07:59:54
【问题描述】:
template<typename T>
someclass<T>& operator=(const someclass<T>& other)
{
typename std::vector<T *>::const_iterator rhs;
typename std::vector<T *>::iterator lhs;
//identity test
//this->data is std::vector<T *>
for(lhs = this->data.begin(); lhs != this->data.end(); lhs++)
{
delete *lhs;
}
this->data.clear(); // this is what I forgot
this->data.reserve(other.data.size());
for (rhs = other.data.begin(); rhs != other.data.end(); rhs++)
{
if (NULL == *rhs)
{
this->data.push_back(NULL);
}
else
{
this->data.push_back(new T(**rhs));
}
}
}
正如您在 cmets 中看到的,我忘记清除数组中的旧指针。当我第二次调用赋值运算符时,我得到了 glibc 错误,抱怨 double free。提供的唯一信息是已删除的地址。
这让我开始思考如何处理此类已删除指针 - 当您不想再次删除它们时,当您这样做时,这肯定是一个错误。您不能将它们设置为 NULL,因为那时另一个删除将是正确的。您不想保留该值,因为可以将内存位置分配给新创建的对象。
对调试有好处的是一些值,比如 INVALID,你分配给这些指针说“在这个指针上调用 delete 是一个错误”,而不是 NULL,它说“在这个指针上调用 delete 什么都不做”。有这样的吗?
【问题讨论】:
-
这不是很可靠——你很容易弄错失效代码,错过你试图捕捉的错误。诸如Valgrind 之类的动态分析工具将可靠地捕获双重删除以及许多其他内存错误。 (当然,正如答案所说,避免手动内存管理将首先防止此类错误)
-
Mike Seymour:对,但假设我在删除后添加了
*lhs = 0。一切都会好起来的,但我会有内存泄漏,甚至 valgrind 都找不到 -
是的,如果您故意掩盖错误,那么您将使其更难找到。你为什么要这样做?
-
这不是故意掩饰。据我所知,删除后将指针设置为 NULL 是一种常见的做法
-
@Dadam:将指针设置为 NULL 可能是一个值得商榷的做法。它会在这里做什么?使容器无限增长。如果用户代码尽职尽责地检查 NULL,结果是您的程序可能运行良好(暂时)但在某种意义上会泄漏内存(内存从未释放并且使用量不断增加)。
标签: c++ pointers memory-management invalidation