2017-08-12 55 views
2

這是我錯過的東西,但我很驚訝。考慮下面的代碼示例:爲什麼在按值傳遞右值時調用的複製構造函數不起作用

#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() */ 

爲什麼不叫當我走過A(2)按值testFunction1()拷貝構造函數?這是否意味着在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的打印成員函數),編譯器仍可以使用複製elision,以實現優化目的。換句話說,不使用arg不是導致此行爲的原因。

如果您使用古老的編譯器,或者鍛鍊當前編譯器的設置,您可能會首先看到預期的結果。

,副本elision將在這種情況下,像Guillaume Racicot提到的保證。

+1

我甚至會提到它保證在他的情況下複製elision在C++ 17 –

+0

@GuillaumeRacicot謝謝,答案改進! =) – gsamaras

相關問題