2017-08-12 8 views
2

何とか見逃したことですが驚いています。次のコード例を考えてみましょう:rvalueを値渡しして関数に渡すときにコピーコンストラクタが呼び出されないのはなぜですか?

#include <iostream> 

class A 
{ 
    int a; 

public: 
    A(int a) : a(a) { std::cout << "Normal constructor called." << std::endl; } 
    A(const A& orig) : a(orig.a) { std::cout << "Copy constructor called." << std::endl; } 
}; 

void testFunction1(const A arg) { std::cout << "testFunction1()" << std::endl; } 
void testFunction2(const A& arg) { std::cout << "testFunction2()" << std::endl; } 

int main() 
{ 
    testFunction1(A(2)); 

    testFunction2(A(2)); 

    return 0; 
} 

私は次のような結果が予想:

/* Normal constructor called. */ 
/* Copy constructor called. */ 
/* testFunction1() */ 
/* Normal constructor called. */ 
/* testFunction2() */ 

をしかし、私は間違っていました。正確な結果は以下の通りであった:

/* Normal constructor called. */ 
/* testFunction1() */ 
/* Normal constructor called. */ 
/* testFunction2() */ 

はなぜtestFunction1()に値によってA(2)を通過したときに呼び出さコピーコンストラクタませんでしたか? C++ 98で値または参照による値を渡すことに違いはないのでしょうか?それは最適化ですか? A(2)argは全く同じのオブジェクトですtestFunction1()

+5

おそらく[* copy elision *](https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization)。 –

+0

@Someprogrammerdude - ありがとう、私はそれをチェックします。前にそれについて聞いたことはありません。 –

+0

あなたはそれについて聞いたことがないなら、あなたは良いC++の本を読むかもしれません... ** Meyers **と** Sutter **の本が強く推奨されます。 – Phil1970

答えて

3

最適ですか?

はい!これはCopy Elisionと呼ばれ、コンパイラーによって可能な限りコピーを省略することができます(バイパスされます)。

あなたのケースでは、コンパイラーは、コピーコンストラクターを呼び出さずに逃げることができることを理解しています。 argを使用した場合でも、例えば、印刷メンバー関数Aを呼び出すような場合でも、最適化の目的で、コンパイラがコピーエリジョンを使用できることに注意してください。つまり、argを使用しないことは、この現象の原因ではありません。

古代コンパイラを使用したり、現在の設定を調整したりすると、最初に期待した結果が表示されます。

では、Guillaume Racicotが述べたように、この場合、コピーのエリミッションが保証されます。

+1

私はそれがC++の彼のケースでコピーelisionを持っていることが保証されていると言いたいと思う17 –

+0

@GuillaumeRacicotありがとう、答えが改善! =) – gsamaras

関連する問題