没有调用复制构造函数

No call to the copy constructor

本文关键字:构造函数 复制 调用      更新时间:2023-10-16

考虑一下:

#include <iostream>
struct A{
   A(){
       std::cout << "Create empty A" << std::endl;
   }
   A(const A& a){
       // Why is this never called??
       std::cout << "Never called" << std::endl;
   }
};
A genA() {
   A a;
   return a;
}
int main(int argc, const char *argv[])
{
   A a(genA()); // Expected to call copy constructor
   return 0;
}

为什么没有调用复制构造函数?

如果我想确保每次复制a时屏幕上都显示"Never called",我该怎么做呢?

这被称为返回值优化
编译器可以优化你的代码,这样它就可以直接在对象被复制的位置构建对象。因此,没有理由使用复制构造函数。

强制编译器避免RVO的一种方法是不按值返回-例如

#include <iostream>
#include <memory>
struct A{
   A() {
       std::cout << "Create empty A" << std::endl;
   }
   A(const A& a) {
       // This will be called now
       std::cout << "Never called" << std::endl;
   }
};
std::auto_ptr<A> genA() {
   return std::auto_ptr<A>(new A);
}
int main(int argc, const char *argv[])
{
   A a(*(genA().get())); // this will trigger the copy-ctor
   return 0;
}

虽然这是一个可怕的黑客。我会问你为什么要这么做?如果您希望在构造函数中加入一些副作用,请不要这样想。

复制构造函数调用可以被省略(即使它们包含副作用),标准允许这样做([12.2])。

编辑:

我建议你不要试图在现实世界的代码中对抗它。

如果你只是想看到复制器在一些示例/教程代码中执行,那么不进行优化编译通常会有所帮助。有些编译器甚至有帮助避免这种情况的开关。对于GCC,应该是-fno-elide-constructors