当前位置: 首页 > 知识库问答 >
问题:

需要一些帮助来理解 C 11 移动构造函数 [重复]

欧浩淼
2023-03-14

作为一个C新手,我真的很难理解C 11的新Move-Constructor,我希望有人可以解释我偶然发现的具体情况。让我们以此示例代码为例:

#include <iostream>

using namespace std;

class Model {
public:
    int data;
    Model(int data) : data(data) { cout << "Constructor" << endl; }
    Model(Model&& model) { cout << "Move constructor" << endl; }
    ~Model() { cout << "Destructor" << endl; }

private:
    Model(const Model& model);
    const Model& operator=(const Model&);

};

Model createModel(int data) {
    return Model(data);
}

int main(void) {
    Model model = createModel(1);
    cout << model.data << endl;
    return 0;
}

因此,我创建了一个 createModel 函数,该函数应将模型作为临时右值返回,并且我想将其分配给左值。我不希望编译器创建 Model 对象的副本,因此我将复制构造函数定义为私有构造函数,并且我对赋值运算符执行相同的操作,以确保不复制任何数据。完成此操作后,代码不再正确编译,因此我添加了 Move 构造函数,现在它再次编译。但是当我运行程序时,我得到这个输出:

Constructor
1
Destructor

所以移动构造函数从未被调用过。我不明白为什么我必须指定移动构造函数才能在运行时根本不使用它时编译程序。

是因为编译器(GCC 4.8.2)把Move构造函数优化走了吗?还是这里表演了其他什么魔术?

那么,有人能解释一下上面代码中到底发生了什么吗?代码可以实现我想要的,但我真的不明白为什么。

共有3个答案

杜高谊
2023-03-14

您是此处返回值优化的“受害者”。

注意这一点:“在C语言中,允许改变结果程序的可观察行为是特别值得注意的”。

编辑:因此,允许编译器应用优化,即使移动ctor(cout)的副作用已更改。

郭子航
2023-03-14

我认为这是你所说的复制省略(即防止复制对象)并直接使用它。请参见:复制省略:在 return 语句中使用三元表达式时未调用移动构造函数?

段干开宇
2023-03-14

您的程序中可能会发生两个动作:

  1. 从函数到返回对象
  2. 从返回对象到模型

出于同样的原因,编译器可以省略这两个步骤:

当尚未绑定到引用(12.2)的临时类对象将被复制/移动到具有相同cv-unqualified类型的类对象时,可以通过将临时对象直接构造到省略的复制/移动的目标中来省略复制/移动操作

存在复制/移动省略的其他情况(参见C 11中的§12.8/31)。请注意,复制/移动省略是完全可选的-编译器不必这样做。

请注意,只要编译器不改变程序的行为(在as-if规则下),就可以绝对优化任何内容。标准中明确提到复制/移动省略的原因是,如果您的复制/移动构造函数有副作用,它可能会改变程序的行为。允许编译器执行此优化,即使它改变了程序的行为。这就是为什么复制/移动构造函数不应该有副作用,因为这样你的程序将有多个有效的执行路径。

您可以将-fno-elide构造函数选项传递给gcc,以确保从不执行此优化。

 类似资料:
  • 我很难理解以下函数的递归工作流程,以及它如何遍历排列排序数组。 让我感到困惑的一件特别的事情是“返回[nums[:]]”调用在递归函数中的行为。由于第9行再次调用自己,直到“start==2”,它什么时候继续执行第9行之后的行,以及它为哪个递归函数执行这些继续行? 抱歉,如果我的问题有点让人困惑,我最近才开始学习Python,希望更好地了解“return”调用在递归函数中的工作方式。任何建议都将不

  • 我正在尝试解决hackerrank中的一个“几乎已排序”的挑战。问题是: 给定一个包含元素的数组,可以只使用以下操作之一按升序对该数组进行排序吗? 交换两个元素。反转一个子段。 输入格式 第一行包含一个整数,指示数组的大小。 下一行包含以空格分隔的整数。 样本输入#1 2 4 2 示例输出 #1 是< br >交换1 2 示例输入 #2 3 3 1 2 样品输出#2 不 示例输入 #3 6 1 5

  • 需要帮助编写一个cassandra udf来添加/除/乘两个变量。尝试下面的代码,但它似乎不工作。而且我没有在Java的经验,所以可能是我不能调试。感谢你的帮助。

  • 我正在使用android Studio学习应用程序开发。 在build.gradle页面上,我遇到了一个错误,即 “编译'com.android.support:appcompat-v7:25.2.0'”

  • 我正在重构前一段时间编写的一些代码,试图通过实现一些设计模式使其更加可靠。具体来说,我尝试使用构建器模式实例化GUI对象。 以下是“产品”的代码: 这是“混凝土建造者”的代码: 以及“抽象生成器”接口的代码: 现在,这里是“Director”的当前工作构建方法: 酷,那有什么问题吗?好吧,这可能最终无关紧要,但这是我对该方法的实际首选实现: 看看它看起来有多干净?唯一的问题是JetBrains无论