2017-08-12 83 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

相关问题