为什么在下面的程序中不调用复制构造函数?
在下面的程序中,为什么复制构造函数没有被调用?
这个问题的原因是由于返回值优化(return value optimisation)导致的。
返回值优化是一种编译器优化技术,它通过将函数返回值直接放在调用方的对象中,而不是先创建一个临时对象,再将临时对象复制到调用方的对象中,从而避免了额外的复制操作。
在本程序中,函数`getValue()`返回一个`MyClass`对象,然后将返回值赋给了`obj`对象。由于返回值优化的存在,编译器会选择直接将返回值放在`obj`对象中,而不是先创建一个临时对象,再复制到`obj`对象中。
因此,由于返回值优化的作用,复制构造函数没有被调用。
要解决这个问题,我们可以使用以下两种方法之一:
1. 使用编译器选项禁用返回值优化。这样,编译器将强制执行复制构造函数的调用。例如,对于GCC编译器,可以使用`-fno-elide-constructors`选项来禁用返回值优化。
2. 修改程序,使其不依赖于返回值优化。可以通过修改函数返回类型为指针或引用,并在函数内部创建一个临时对象,然后返回指针或引用。
下面是一个示例代码,演示了如何修改程序来解决这个问题:
#includeclass MyClass { public: MyClass() { std::cout << "Default constructor called" << std::endl; } MyClass(const MyClass& other) { std::cout << "Copy constructor called" << std::endl; } }; MyClass getValue() { MyClass temp; return temp; } int main() { MyClass obj = getValue(); return 0; }
在上述修改后的程序中,函数`getValue()`返回一个指向`MyClass`对象的指针。在函数内部,创建了一个临时对象`temp`,然后返回了指向`temp`的指针。
在`main()`函数中,通过将返回的指针赋给`obj`对象,实现了与原始程序相同的功能。由于不再依赖于返回值优化,复制构造函数将被调用。
通过以上的修改,我们可以确保复制构造函数被正确调用,从而解决了原始程序中复制构造函数没有被调用的问题。
为什么在以下程序中没有调用复制构造函数?
在这里发生了两次复制省略。
第一次是一种返回值优化(不是将表达式Test()
的结果复制到作为返回值的临时对象中,而是通过直接构造返回值作为返回值的临时对象来计算Test()
的表达式)。
第二次是从t1
的初始化表达式到t1
本身的复制省略(所以不是将作为返回值的临时对象复制到t1
中,而是直接构造作为返回值的临时对象到t1
中)。
这两个省略链在一起 - 所以t1
的内存用作构造f
的返回值的目标,并且f
的返回值的内存用作构造Test()
的目标。因此,实际上t1
是通过无参构造函数进行直接初始化的,不需要进行任何复制。
复制构造函数省略在C++03的第12.8/15节和C++11的第12.8/31节中定义(也允许省略移动)。它需要特定的许可,因为它会改变程序的可观察行为(在您的情况下,省略了复制构造函数的副作用,即输出)。因此,它只能在标准中定义的条件下执行。
这两个省略都是C++03中允许的第二种省略的例子(C++11中为第三种),当源是临时对象时。
第一个允许的省略通常称为“命名返回值优化”,它允许在源不是临时对象时省略特定类型的复制。