2012-02-19 87 views
3

下面的代码给出了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。请注意,复制构造函数永远不会被调用,它会打印出一条消息。

+0

您可以确保您发布了您正在使用的确切代码。没有返回类型的'main'应该会产生一个编译错误。 – 2012-02-19 11:50:08

+1

...对于那些认为在NULL上调用'delete []'是错误的人:**“在任何一种替代[delete和delete []]中,如果delete的操作数的值是空指针,则操作没有任何效果。“** – LihO 2012-02-19 12:01:18

回答

1

保利创造了3次Poly a;的主。 Poly c;fun()。并且在分配函数的结果之前。所以有3个析构函数。

这种行为是确定的,但某些编译器可能会优化此过程。

+2

我不会调用程序的行为不行,还有_undefined behavior_。 – 2012-02-19 12:01:31

6

它看起来像你的“保利运营商=”不返回任何东西。

+0

谢谢!这解决了这个问题。 – Ekalavya 2012-02-19 12:02:54

+0

不客气。 – innochenti 2012-02-19 15:10:59

0

在此代码:

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

没有返回值优化:

  1. 一个创建
  2. c为创建的C
  3. 副本创建
  4. c的破坏
  5. 将c的副本分配到
  6. 的C拷贝被破坏
  7. 被破坏

与返回值优化:创建

  1. 一个创建
  2. Ç
  3. C分配到
  4. c的破坏
  5. 一个是DES tructed

还要注意的是operator=应该是这样的:

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

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

+0

非常感谢!这是一个超级社区。 – Ekalavya 2012-02-19 11:41:22

+0

@ user1219083:不客气;) – LihO 2012-02-19 11:42:19

+2

'operator ='应该总是返回一个非const引用来与[兼容标准容器](http://stackoverflow.com/questions/2969387/why-operator-returns-reference -not const的参考)。 – 2012-02-19 12:08:14

2

主要问题是在赋值运算符。它返回Poly by value,但您从不指定任何内容。

所以,在这一行a = a.fun();我们得到新的Poly作为operator=的结果。这个临时变量立即退出范围,因此它的析构函数被调用。但是,因为你没有从operator =返回一些东西,所以暂时还没有建成。

我建议您在编译时使用-Wall参数gcc打开所有警告,并返回参考operator=,而不是临时的。

+0

我喜欢这个解释。哇!谢谢。 – Ekalavya 2012-02-19 12:20:15

3

你的程序有两个实际的错误。首先是main需要声明为返回int

第二个问题是您的复制赋值运算符未声明为返回void,但控制权在不执行return语句的情况下离开该函数。这导致未定义的行为,因此您看到的不可预测的影响。


几乎可以确定你想要你的拷贝赋值运算符的价值,并return *this;返回一个参考,而不是一个对象。虽然技术上你可以按价值归还任何物品,但它会是非常传统的。

显然,你的拷贝构造函数和拷贝赋值操作符还没有在实现中做任何有用的拷贝,但我认为这是因为代码是用于测试或“尚未实现”的。

相关问题