简体   繁体   English

初始化具有函数返回值的对象时未复制的复制构造函数

[英]Copy constructor not called when initializing an object with return value of a function

Consider the following code: 请考虑以下代码:

#include <iostream>

using namespace std;

class A
{
    public:
        int a;
        A(): a(5)
        {
           cout << "Constructor\n";
        }
        A(const A &b)
        {
            a = b.a;
            cout << "Copy Constructor\n";
        }
        A fun(A a)
        {
            return a;
        }
};

int main()
{
    A a, c;
    A b = a.fun(c);
    return 0;
}

The output of the above code with g++ file.cpp is: 上面代码与g++ file.cpp的输出是:

Constructor
Constructor
Copy Constructor
Copy Constructor

The output of the above code with g++ -fno-elide-constructors file.cpp is: 上面代码与g++ -fno-elide-constructors file.cpp是:

Constructor
Constructor
Copy Constructor
Copy Constructor
Copy Constructor

I know Return Value Optimization. 我知道返回值优化。 My question is which call to copy constructor is elided(temporary object during returning or returned object being copied to b)? 我的问题是哪个复制构造函数的调用被删除(返回期间的临时对象或被复制到b的返回对象)?

If the elided copy constructor is the one used for creating b, then how is b created at all (because there is no constructor call in this case also)? 如果省略的复制构造函数是用于创建b的构造函数,那么如何创建b(因为在这种情况下也没有构造函数调用)?

If I replace the line A b = a.fun(c); 如果我更换线A b = a.fun(c); with a.fun(c) and compile using the first method or even the second method, then also the copy constructor is being called 2 times . 使用a.fun(c)并使用第一种方法甚至第二种方法进行编译,然后复制构造函数被调用2次。 So, if in the case explained in the previous paragraph, the temporary object's copy constructor is elided, then why isn't it elided in this case? 因此,如果在上一段中解释的情况下,临时对象的复制构造函数被省略了,那么为什么在这种情况下它没有被省略呢?

#include <iostream>

using namespace std;

class A
{
public:
    int a;
    A(): a(5)
    {
        cout << "Constructing: " << (void *)this << std::endl;
    }
    A(const A &b)
    {
        a = b.a;
        cout << "Copy Constructor: " << (void *)this << " from " << (void *)&b << std::endl;
    }
    A fun(A a)
    {
        return a;
    }
};

int main()
{

    A a, c;
    A b = a.fun(c);

    std::cout << "a:" << (void *)&a << std::endl <<
              "b:" << (void *)&b << std::endl <<
              "c:" << (void *)&c << std::endl;
    return 0;
}

Yields: 产量:

Constructing: 0x7fffbb377220
Constructing: 0x7fffbb377210
Copy Constructor: 0x7fffbb377230 from 0x7fffbb377210
Copy Constructor: 0x7fffbb377200 from 0x7fffbb377230
a:0x7fffbb377220
b:0x7fffbb377200
c:0x7fffbb377210

So it constructs a , constructs c , copies c to an intermediate (argument a of the function), and then copies the intermediate directly into b , skipping the typical copying of a to a return intermediate. 所以它构造a ,构建c ,拷贝c到中间(自变量a函数),然后复制中间体直接进入b ,跳过的典型拷贝到中间回报。 This is even better demonstrated if you pass by value (change to A fun(const A& a) : 如果你传递值,则更好地证明了这一点(改为A fun(const A& a)

Constructing: 0x7fff8e9642b0
Constructing: 0x7fff8e9642a0
Copy Constructor: 0x7fff8e964290 from 0x7fff8e9642a0
a:0x7fff8e9642b0
b:0x7fff8e964290
c:0x7fff8e9642a0

a is constructed, c is constructed, c is copied directly to b, despite b not being passed to fun! a构造,c构造,c直接复制到b,尽管b没有传递给乐趣!

The copy that is elided is the copy of the temporary return value into b . 省略的副本是临时返回值到b的副本。 Without elision the return value is initialized from a and copied to b . 如果没有省略,则返回值从a初始化并复制到b Instead, the temporary that would otherwise hold the return value is constructed into b and initialized with a . 相反,将保存返回值的临时值构造为b并用a初始化 [class.copy]/31: [class.copy] / 31:

when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move 当一个未绑定到引用(12.2)的临时类对象被复制/移动到具有相同cv-nonqualified类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动

You can observe this if you add an additional output in fun : 如果您在fun添加其他输出,则可以观察到此情况:

A fun(A a)
{
    cout << "fun!" << endl;
    return a;
}

Then with the elision you'll get 然后你将获得elision

[…] [...]
fun! 乐趣!
Copy Constructor 复制构造函数

And without: 没有:

[…] [...]
fun! 乐趣!
Copy Constructor 复制构造函数
Copy Constructor 复制构造函数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 按值返回时不调用复制构造函数 - Copy constructor is not called when return by value 为什么在按值从方法返回对象时调用复制构造函数 - Why is the copy constructor called when we return an object from a method by value 为什么复制构造函数总是在按值返回时调用 - why copy constructor is always called when return by value 什么时候在C ++中调用复制构造函数? -函数返回 - When is a copy constructor called in C++? - Function return 当从 function 返回 object 时,会调用 C++ 中的复制构造函数? - Copy Constructor in C++ is called when object is returned from a function? 从函数返回对象时调用复制构造函数? - Copy constructor is called when returning object from a function? 当从函数参数中的临时值调用复制构造函数时 - When copy constructor is called from a temporary value in function argument 设置对象等于另一个函数的返回值时,为什么调用移动构造函数/赋值 - Why is the move constructor/assignment called when setting an object equal to the return value of another function 使用函数返回值初始化std :: string,是否有副本? - Initializing a std::string with function return value, is there a copy? 当函数按值返回时,复制构造函数是否执行? - Is copy constructor execute when the function is return-by-value?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM