【问题标题】:Trying to delete already-deleted pointer in destructor试图删除析构函数中已删除的指针
【发布时间】:2013-10-01 12:01:27
【问题描述】:

我有以下类,当调用析构函数并尝试删除指向 a 和 b 的指针时出现错误。看起来它们不存在。 这是触发问题的代码行

unordered_map<string,Stock>* SDict = new unordered_map<string,S>();
SDict->insert(make_pair("38363",S("38363",i,w)));

标题

class O{
public:
    O();
    ~O();
    O(const O& tocopy);
    O& operator=(const O& toassign);


private:
    unordered_map<int,PQL>* b;
    unordered_map<int,PQL>* a;
};

来源

O::O(){
    a = new unordered_map<int,PQL>();
    b = new unordered_map<int,PQL>();
}

O::~O(){
    delete b; //I get the exception here- b doesn't exist before the delete.
    delete a;
}

O& O::operator=(const O& src){
    if(this != &src){
        delete b;
        delete a;

        b = new unordered_map<int,PQL>();
        b = src.b;
        a = new unordered_map<int,PQL>();
        a = src.a;
    }
    return *this;
}

O::O(const O& src){
    b = new unordered_map<int,PQL>();
    b = src.b;
    a = new unordered_map<int,PQL>();
    a = src.a;
}

PQL 是一个只有三个整数的类。是否有明显的原因导致此错误?

类 O 是以下类的数据成员:

标题

class S{
    public:
        S();
        S(string sid, vector<string>* indexids, vector<double>* sw);
        ~S();
        S(const S& tocopy);
        S& operator=(const S& toassign);

    private:
        string sid;
        O* o;
        vector<Strategy*> ts;
        unordered_map<string,double>* iw;
};

来源

    S::S(){}

    S::S(string sid, vector<string>* iis, vector<double>* sw){
        sid = sid;
        iw = new unordered_map<string,double>();
        o = new o();

        if(iis->size() == sw->size()){
            for(size_t i=0; i<iis->size(); i++){
                string key = iis->at(i);
                if(iw->count(key) == 0 ){
                    double weighting = sw->at(i);
                    iw->insert(make_pair(key,weighting));
                }
                else{
                    throw new exception();
                }
            }
        }
        else{
            throw new exception();
        }
    }

    S::S(const S& rhs){
        sid = rhs.sid;
        ts = rhs.ts;
        o = new O();
        o = rhs.o;
        iw = new unordered_map<string,double>();
        iw = rhs.iw;
    }

    S& S::operator=(const S& src){

        if(this != &src){
            delete o;
            delete iw;

            sid = src.sid;
            ts = src.ts;
            o = new o();
            o = src.o;
            iw = new unordered_map<string,double>();
            iw = src.iw;
        }

        return *this;
    }

    S::~S(){
        delete o;
        delete iw;
    }

【问题讨论】:

  • 我编辑了我的答案以包括 unordered_map 插入(我认为这是创建一个临时 S 对象,这会导致调用复制构造函数和析构函数。
  • 哇,我不记得我是否在我的生活中看到了更多的内存泄漏o_O
  • 您的复制构造函数不是复制地图,而是复制指针(并泄漏您刚刚分配的地图)。复制行需要为b = new unordered_map&lt;int,PQL&gt;(*src.b);(类似更改a 的分配)。但是为什么你的类包含指向地图的指针,数据成员应该是unordered_map&lt;int,PQL&gt; b;
  • @Everyone-我是一个新手 C++ 程序员,所以欢迎所有有建设性的 cmets
  • Pointers... pointers everywhere. 但说真的,这么多裸指针,甚至不值得修复代码。只需重写所有内容以使用引用、自动变量或unique_ptr/shared_ptr

标签: c++ copy destructor copy-constructor deep-copy


【解决方案1】:

你的拷贝构造函数有一个明显的问题:

O::O(const O& src){
    b = new unordered_map<int,PQL>();
    b = src.b;
    a = new unordered_map<int,PQL>();
    a = src.a;
}

分配确实分配了错误的实体:它分配了指针,即分配b = src.b 泄漏了刚刚分配的内存并复制了指针。你可能打算写:

O::O(O const& src)
    : b(new std::unordered_map<int, PQL>(*src.b)
    , a(new std::unordered_map<int, PQL>(*src.a)
{
}

请注意,您的赋值运算符不是异常安全的!一般的猜想是,如果您的代码需要检查自赋值以在自赋值的情况下工作,那么它就不是异常安全的。

赋值的规范实现利用复制构造函数和析构函数,并使用另一个常用函数swap() 来交换资源:

O& O::operator= (O other) {
    this->swap(other);
    return *this;
}
void O::swap(O& other) {
    using std::swap;
    swap(this->b, other.b);
    swap(this->a, other.a);
}

【讨论】:

  • 您能否详细说明您对异常安全的评论?我有兴趣。
  • @user997112:如果在分配/复制std::unordered_map&lt;...&gt;s 时抛出异常,则对象最终处于不一致状态:对象已经是deleted,无法恢复。
  • 您可能会补充说,他的代码的第一个问题是他在不应该使用动态分配时使用了动态分配。几乎从不存在您想要动态分配其中一个标准容器的情况。
  • 谢谢詹姆斯,我没有意识到这一点。
【解决方案2】:

以下代码:

   b = new unordered_map<int,PQL>();
   b = src.b;
   a = new unordered_map<int,PQL>();
   a = src.a;

应改为:

   b = new unordered_map<int,PQL>();
   *b = *src.b;
   a = new unordered_map<int,PQL>();
   *a = *src.a;

在复制 ctor 和赋值运算符中。所以它会复制地图内容而不是复制指针,这是错误的行为。但更好的方法是:

   b = new unordered_map<int,PQL>( *src.b );
   a = new unordered_map<int,PQL>( *src.a );

【讨论】:

    【解决方案3】:

    你的代码有几个问题

    O& O::operator=(const O& src){
    if(this != &src){
        delete b;
        delete a;
        //b will point to newly allocated memory
        b = new unordered_map<int,PQL>();
        //now you set b to point to the same unordered map as src (double deletion will occur)
        //you will leak the memory you just allocated
        b = src.b;
    

    复制构造函数也有同样的问题...

    【讨论】:

      【解决方案4】:

      您的复制构造函数是错误的。你需要做一个深拷贝,而不是仅仅使用像

      这样的东西
      b = src.b;
      

      您需要将地图的每个成员从源复制到目标。

      还有你的赋值运算符。

      【讨论】:

      • 不,您不需要复制地图中的每个元素,unordered_map 有一个复制构造函数可以为您完成。
      • 确实如此。但是那个构造函数仍然复制每个元素,对吧?
      猜你喜欢
      • 2014-12-30
      • 1970-01-01
      • 2021-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      • 1970-01-01
      • 2013-10-10
      相关资源
      最近更新 更多