为什么不调用复制构造函数 [英] Why is copy constructor not called
问题描述
这是一个简单的类头文件和一个主程序。在主程序中,我认为复制构造函数在以下三种情况下被调用:初始化(显式复制),函数参数按值传递和函数按值返回。但是,似乎并没有要求其中之一,我认为注释中的编号是(3)或(4)。它针对哪个数字(1)-(4)?
Here is a simple class header file and a main program. In the main program, I thought that the copy constructor is called in exactly three situations: initialization(explicit copy), pass by value for function arguments, and return by value for functions. However it seems like it is not being called for one of them, I think either (3) or (4) as numbered in the comments. For which numbers (1) - (4) does it get called? Thanks.
X.h:
#include <iostream>
class X
{
public:
X() {std::cout << "default constructor \n";}
X(const X& x) { std::cout << "copy constructor \n";}
};
主要:
#include "X.h"
X returnX(X b) // (1) pass by value - call copy constructor?
{
X c = b; // (2) explicit copy - call copy constructor?
return b; // (3) return by value - call copy constructor?
}
int main()
{
X a; // calls default constructor
std::cout << "calling returnX \n\n";
X d = returnX(a); // (4) explicit copy - call copy constructor?
std::cout << "back in main \n";
}
输出:
default constructor
calling returnX
copy constructor
copy constructor
copy constructor
back in main
推荐答案
由于复制在C ++中经常发生,因此编译器可能会很昂贵允许删除某些复制(和移动)结构。即使删除的构造函数和/或析构函数具有副作用(例如程序中的输出),也允许使用此复制省略号(也就是说,这实际上不是一种优化,因为使用和不使用复制删除项的行为都不同)。
Since copying happens frequently in C++ and since it may be expensive the compiler is allowed to elide certain copy (and move) constructions. This copy elision is allowed even if the elided constructor and/or the destructor has side effects like the output in your program (that is, it isn't really an optimization as the behavior with and without copy elision is different).
根据12.8 [class.copy]第31段,可以在四个基本位置应用复制省略:
There are four basic places where copy elision can be applied according to 12.8 [class.copy] paragraph 31:
- 在直接返回与该函数的返回类型相同类型的局部变量的
return
语句中。 - 在
throw
语句中,当以下位置时,可以省去最里面的try
块内的自动变量副本: - 当临时对象未绑定到引用时,可以将其删除。
- 当
catch
子句按值捕获对象,并且类型与throw
语句中的对象相同,可以删除副本。
- In a
return
statement when directly returning a local variable which has the same type as the return type of the function. - In a
throw
statement a copy of an automatic variable within the innermosttry
-block can be elided when the object is thrown. - When a temporary object wasn't bound to a reference copying it can be elided.
- When a
catch
clause catches the object by value and with the same type as the object in thethrow
statement the copy can be elided.
确切的规则是稍微复杂一点,但是我认为这是要点。鉴于复制省略的规则相当严格,因此抑制复制省略很容易:最简单的方法是使用 identity()
函数:
The exact rules are slightly more complicated but I think this is the gist of it. Given that the rules for copy elision are fairly strict it is easy to suppress copy elision: the easiest way is to use an identity()
function:
template <typename T>
T const& identity(T const& object) {
return object;
}
...
X d = identity(returnX(a));
(此版本也禁止移动构造;使用推导类型T&
并适当地返回它应该可以进行移动构造,但是我不确定返回类型和return语句应该是什么。)
(this version also inhibits move construction, though; deducing the type using a T&&
and returning it appropriately should make move construction possible but I'm not quite sure what the return type and the return statement should be).
这篇关于为什么不调用复制构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!