将右值按值传递给函数时,为啥不调用复制构造函数

Posted

技术标签:

【中文标题】将右值按值传递给函数时,为啥不调用复制构造函数【英文标题】:Why isn't the copy-constructor called when passing rvalue by value to function将右值按值传递给函数时,为什么不调用复制构造函数 【发布时间】:2018-01-20 20:12:48 【问题描述】:

这是我不知何故错过的一件事,但我很惊讶。考虑以下代码示例:

#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() 中的对象吗?

【问题讨论】:

可能是copy elision @Someprogrammerdude - 谢谢,我会检查的。以前从未听说过。 如果您从未听说过,那么您可能会阅读一些不错的 C++ 书籍...强烈推荐 MeyersSutter 书籍。跨度> 【参考方案1】:

是优化吗?

是的!它被称为 Copy Elision,如果可能,根据编译器,可以省略(绕过)副本。

因此,在您的情况下,编译器知道它可以在不调用复制构造函数的情况下逃脱,并且正是这样做的。请注意,即使您使用了arg,例如调用A 的打印成员函数,编译器仍然可以使用复制省略来进行优化。换句话说,不使用arg 并不是造成这种行为的原因。

如果您使用古老的编译器,或调整当前编译器的设置,您可能会首先看到预期的结果。

使用c++17,在这种情况下可以保证复制省略,正如 Guillaume Racicot 提到的那样。

【讨论】:

我什至要提一下,在他的情况下,在 C++17 中可以保证复制省略

以上是关于将右值按值传递给函数时,为啥不调用复制构造函数的主要内容,如果未能解决你的问题,请参考以下文章

当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?

为啥不允许将数组按值传递给 C 和 C++ 中的函数?

没有调用复制构造函数?

按值传递参数时的奇怪行为

函数不将右值引用作为参数? [复制]

选择 Java 函数调用中的按值传递行为