【问题标题】:Relationship between copy initialization and copy constructor [duplicate]复制初始化和复制构造函数之间的关系[重复]
【发布时间】:2020-09-29 16:29:52
【问题描述】:
#include <iostream>

class Test {
public:
    Test(const int& i) 
    {
        std::cout << "Direct" << std::endl;
    }
    Test(const Test& t) 
    {
        std::cout << "Copy" << std::endl;
    }
};

int main()
{
    Test test = 1;
    return 0;
}

这个程序(用C++11编译)只会输出Direct,但是Test test = 1;意味着隐式转换1到测试然后将结果复制到test,我希望它同时输出@987654327 @和Copy,谁能解释一下?

【问题讨论】:

  • 您要查找的搜索词是“复制省略”。复制构造函数(和相应的析构函数)在看起来应该调用时不被调用是合法的,并且在某些情况下是必需的。例如,请参阅 cppreference.com 上的 copy elision
  • 那么这种行为的目的仅仅是为了性能?我必须在任何构造函数中做同样的事情?
  • “仅用于性能” - 我的意思是,是吗?!这是 C++,我们力求获得最佳性能。甚至在概念上,创建一个临时对象有什么用处,它只是为了初始化 另一个 对象,然后立即被销毁?!还不如将整个初始化折叠为单个 c'tor 调用。
  • 是的,复制省略是一种性能优化。我不明白你的问题“我必须做同样的事情......?” - 你不需要做任何事情,编译器会做优化。

标签: c++


【解决方案1】:

直到c++17,这个初始化:

Test test = 1;

将从int 1 创建一个临时的Test,然后为test 调用复制构造函数。在实践中,编译器会进行复制省略,而临时的将被省略。您可以通过传递 -fno-elide-constructors 标志来强制编译器不执行省略,以查看两个构造函数调用。

从c++17开始,写法变了,右边根本没有临时的,所以没有什么可以省略的,只调用了一个构造函数。所以即使你使用-fno-elide-constructors,你也只会看到一个构造函数调用。

【讨论】:

  • 我认为 Test test = 1; 从 C++11 开始即使没有复制省略也会直接构造!我记错了吗?
  • @MooingDuck 我认为即使在 C++11 之前也是如此。这只是copy initialization
  • @MooingDuck - 你是。尝试在 C++11 中使用已删除/无法访问的副本 c'tor,您应该会收到错误消息。这表明整个事情都是一种优化(而不仅仅是必须发生的行为)。
  • C++11 §12.6.1 专门将 complex f = 3; 称为初始化程序,这让我感到困惑,但你说得对,它澄清了:construct complex(3) using complex(double) copy/move it into f。 §8.5.14 同样说“初始化的形式(使用括号或 =)通常是无关紧要的,但当初始化器或被初始化的实体具有类类型时确实很重要”。 §8.5.15 同意“......称为复制初始化。[注意:复制初始化可能会调用移动(12.8)。-结束注释]”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-06
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多