为什么不调用复制构造函数 [英] Why is copy constructor not called

查看:142
本文介绍了为什么不调用复制构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个简单的类头文件和一个主程序。在主程序中,我认为复制构造函数在以下三种情况下被调用:初始化(显式复制),函数参数按值传递和函数按值返回。但是,似乎并没有要求其中之一,我认为注释中的编号是(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:


  1. 在直接返回与该函数的返回类型相同类型的局部变量的 return 语句中。

  2. throw 语句中,当以下位置时,可以省去最里面的 try 块内的自动变量副本:

  3. 当临时对象未绑定到引用时,可以将其删除。

  4. catch 子句按值捕获对象,并且类型与 throw 语句中的对象相同,可以删除副本。

  1. In a return statement when directly returning a local variable which has the same type as the return type of the function.
  2. In a throw statement a copy of an automatic variable within the innermost try-block can be elided when the object is thrown.
  3. When a temporary object wasn't bound to a reference copying it can be elided.
  4. When a catch clause catches the object by value and with the same type as the object in the throw 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆