繁体   English   中英

隐藏的移动建筑

[英]Hidden move-construction

为什么有时候不会移动构造函数调用? 测试move-semantics (实时代码)

struct Test {
    int id;
    Test(int id) : id(id) {
        cout << id << "  Test() " << endl;
    }
    ~Test() {
        cout << id << "  ~Test() " << endl;
    }
    Test(const Test &t) : id(t.id) {
        cout << id << "  Test(const Test &t) " << endl;
    }
    Test(Test &&t) : id(t.id) {
        cout << id << "  Test(Test &&t) " << endl;
    }
    Test &operator=(const Test &t) {
        cout << id << "  operator=(const Test &t) " << endl;
        return *this;
    }
    Test &operator=(Test &&t) {
        cout << id << "  operator=(Test &&t) " << endl;
        return *this;
    }
};

void f(Test z) {
    cout << z.id << "  f(Test z) " << endl;
}

int main() {
    f(Test(1));

    Test t(2); f(t);
}

输出:

1  Test() 
1  f(Test t)               <---// where is move constructor ?!
1  ~Test() 
2  Test() 
2  Test(const Test &t)     <---// copy constructor of t(2)
2  f(Test t) 
2  ~Test() 
2  ~Test()

测试显示复制构造函数被调用。

但是,在f(Test(1));之后f(Test(1)); 调用函数f而不为Test(1) rvalue对象调用move-constructor。

它是隐式编译器优化吗? 或者我错过了重要的一点?

明确允许编译器忽略临时对象的复制(或移动)。 基本上,对象是在预期有效结果的地方构建的。 如果构造函数或析构函数具有副作用,则甚至允许使用此省略。

相关条款是12.8 [class.copy]第31段:

当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用。 在这种情况下,实现将省略的复制/移动操作的源和目标视为仅仅两种不同的引用同一对象的方式,并且该对象的销毁发生在两个对象的后期时间。没有优化就被破坏了。 在下列情况下允许复制/移动操作(称为复制省略)的这种省略(可以组合以消除多个副本):...

基本上可以使用复制省略的情况

  1. return语句时返回临时变量或局部变量。
  2. throw表达式时抛出临时变量或局部变量。
  3. 何时复制临时对象。
  4. 按值捕获对象时。

可以省略副本的确切条件列于12.8 [class.copy]第31段。

防止复制/移动省略的最简单方法是将其传递给返回合适引用的函数,例如,使用

f(std::move(Test(1)));

应该防止移动省略。

完成此讨论。 我们可以通过此选项在gcc中禁用此优化(复制省略):

-fno-elide-constructors

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM