2012-09-24 17 views
10
#include<iostream> 
using namespace std; 

class A{ 
public: 
    static int cnt; 
    A() 
    { 
     ++cnt; 
     cout<<"constructor:"<<cnt<<endl; 
    } 
    ~A() 
    { 
     --cnt; 
     cout<<"destructor:"<<cnt<<endl; 
    } 
}; 

int A::cnt = 0; 

A f(A x){ 
    return x; 
} 
int main(){ 
    A a0; 
    A a1 = f(a0); 
    return 0; 
} 

プログラムが出力されます:デストラクタがコンストラクタより頻繁に呼び出されるように見えるのはなぜですか?

 
constructor:1 
destructor:0 
destructor:-1 
destructor:-2 

コンストラクタとデストラクタはペアで表示されないのですか?

+0

ようこそスタックオーバーフロー! +1と完全なサンプルプログラムを提供していただきありがとうございます。それがなぜ重要だったのかについては、http://SSCCE.ORGを参照してください。 –

+1

'return x;'によって呼び出されたコピーコンストラクタはすでに明らかに最適化されていますが、十分に積極的なオプティマイザが 'f'(' x'が値渡し)を呼び出すときに呼び出しを取り除くことができるかどうか疑問です。そのため、効果的にデフォルトのデストラクタを呼び出してからコピーコンストラクタを呼び出します。 –

+1

@FrerichRaabe:その最適化は、特定の状況でのみコピーコンストラクタのエリートを許可する標準に準拠しないことになります。許可されたすべての状況において、省略されたコピーのソースまたは宛先は一時的なものです。 –

答えて

14

カウンタを増やすコピーコンストラクタを追加する必要があります。

A(const A&) 
{ 
    ++cnt; 
    cout<<"copy constructor:"<<cnt<<endl; 
} 

明示的に追加しない場合、コンパイラはカウンターcntで何もしない1を生成します。

この式

A a1 = f(a0); 

は、コピーコンストラクタを利用するa0のコピーを、作成しています。正確なコピー数はcopy elisionに応じて異なる場合がありますが、cntはプログラムの最後に0になります。

:あなたがあなた自身のコピーコンストラクタを宣言したら、C++ 11では、あなたも移動、コピーコンストラクタ生成されたコンパイラの可能性を検討すべきであるが、しかし、コンパイラは、もはや移動バージョンを生成しません。

3

コピーコンストラクタコールもカウントする必要があります。 C++ 11では、移動コンストラクタも考慮に入れる必要があります。

5

すべてのコンストラクタはトラッキングされておらず、デフォルトコンストラクタのみがトラッキングされています。コンパイラーはコピーコンストラクターを生成し、それを数回使用して、破壊されたとしてリストされた2つのオブジェクトを考慮に入れました。

関連する問題