析构函数被调用在未构造的东西上

时间:2012-02-19 11:14:40

标签: c++ destructor

以下代码为g ++版本4.6.2提供了一个例外,但是在g ++版本4.2.1中按预期运行。在执行期间打印的消息表明在两种情况下都在从未构造的地址上调用析构函数。我想知道(a)哪些编译器是正确的,(b)为什么某些东西在没有被创建的情况下被破坏。非常感谢。

//------------------------------------------------------
#include <iostream>
using namespace std;

class Poly{
 private:
  float *coeff;
 public:
  Poly(){
    coeff = NULL;
    cout << "Created "<< this << endl;
  }
  Poly(Poly const & p){          // copy constructor
    coeff = NULL;
    cout << "Executed copy constructor.\n";
  }
  Poly operator=(Poly const & rhs){
    cout << "Executed assignment. " << this << " = " << &rhs << endl;
  }
  Poly fun(){
    Poly c;
    return c;
  }
  ~Poly(){
    cout << "Destructor: " << this << endl;
    delete[] coeff;
  }
};


main(){
  Poly a;
  a = a.fun();
}
//------------------------------------------------------

对于g ++ 4.6.2,它给出了例外:

% ./a.out
Created 0xbfdcc184
Created 0xbfdcc18c
Executed assignment. 0xbfdcc184 = 0xbfdcc18c
Destructor: 0xbfdcc188
*** glibc detected *** free(): invalid pointer: 0xbfdcc1a8 ***
Aborted

对于g ++ 4.2.1,它执行以下操作

% ./a.out
Created 0x7fff5fbff930
Created 0x7fff5fbff920
Executed assignment. 0x7fff5fbff930 = 0x7fff5fbff920
Destructor: 0x7fff5fbff910
Destructor: 0x7fff5fbff920
Destructor: 0x7fff5fbff930

没有例外,如果有更多代码,它确实会产生正确的答案。但是,它似乎正在破坏从未构建过的0x7fff5bff910。请注意,永远不会调用复制构造函数,如果存在,则会打印一条消息。

5 个答案:

答案 0 :(得分:6)

看起来你的“Poly operator =”没有返回任何内容。

答案 1 :(得分:3)

您的计划有两个实际错误。第一个是main需要声明为返回int

第二个是你的副本赋值运算符没有被声明为返回void,但是控制在不执行return语句的情况下离开了函数。这会导致未定义的行为,从而导致您看到的不可预测的效果。


您几乎肯定希望您的复制赋值运算符按值返回引用而不是对象,并返回return *this;。虽然从技术上讲你可以按价值返回任何Poly对象,但这将是非常不同寻常的。

很明显,您的复制构造函数和复制赋值运算符尚未在实现中进行任何有用的复制,但我认为这是因为代码用于测试或“尚未实现”。

答案 2 :(得分:2)

主要问题在于赋值运算符。它会返回Poly by value,但您永远不会为其分配内容。

因此,在这一行a = a.fun();中,我们得到了Poly operator=的新结果operator =。这个临时变量立即退出范围,因此它被析构函数调用。但是,由于您没有从-Wall返回某些内容,因此未构建此临时内容。

我建议您在使用gcc参数operator=进行编译时打开所有警告,并从{{1}}返回引用,而非临时。

答案 3 :(得分:1)

Poly在主要版本中创建了3次Poly a;Poly c;中的fun()。并在分配功能结果之前。所以有3个析构函数。

这种行为没问题,但有些编译器可能会优化此过程。

答案 4 :(得分:0)

在此代码中:

Poly fun(){
Poly c;
return c;
}
...
Poly a;
a = a.fun();

没有返回值优化:

  1. a已创建
  2. c已创建
  3. 创建了c的副本
  4. c被破坏
  5. 将c的副本分配到
  6. c的副本被破坏
  7. a被毁坏
  8. 带有返回值优化:

    1. a已创建
    2. c已创建
    3. c被分配到
    4. c被破坏
    5. a被毁坏
    6. 另请注意,operator=应如下所示:

      Poly& operator=(const Poly& rhs){
          cout << "Executed assignment. " << this << " = " << &rhs << endl;
          return *this;
      }
      

      我建议您使用std::vector而不是简单的数组。我还建议您使用double而不是float。如果你这样声明coeffstd::vector<double> coeff;那么你不需要为它分配内存,你不需要显式初始化它,你也不需要删除它。