3
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));
        }
    }
}

正如您在评论中看到的,我忘记清除数组中的旧指针。当我第二次调用赋值运算符时,我得到了 glibc 错误,抱怨 double free。提供的唯一信息是已删除的地址。

这让我开始思考如何处理此类已删除指针 - 当您不想再次删除它们时,当您这样做时,这肯定是一个错误。您不能将它们设置为 NULL,因为那时另一个删除将是正确的。您不想保留该值,因为可以将内存位置分配给新创建的对象。

对调试有好处的是一些值,比如 INVALID,你分配给这些指针说“在这个指针上调用 delete 是一个错误”,而不是 NULL,它说“在这个指针上调用 delete 什么都不做”。有这样的事情吗?

4

2 回答 2

6

不。一个更好的主意是当你想要拥有所有权语义时不使用原始指针。如果您将类型data设为 beboost::ptr_vector<T>std::vector<std::unique_ptr<T>>then 您将不必手动管理指针的生命周期,问题就会消失。

您的容器不能正确支持多态对象,因为您提供的赋值运算符将在容器中的对象分配给另一个容器时对其进行切片。一个更好的解决方案可能是只拥有一个std::vector<T>. 仅当您不依赖指针容器的某些其他属性(例如指向元素的指针的非无效或可能更快的排序操作)时,这才是合适的。

于 2011-10-11T08:07:21.723 回答
2

这个问题的解决方案是编写不包含任何删除的代码。尽可能使用shared_ptr。当你有一个拥有多态对象的容器时,你也可以使用Pointer Container

于 2011-10-11T08:07:49.803 回答