【问题标题】:How to move temporary object without std::move [duplicate]如何在没有 std::move 的情况下移动临时对象 [重复]
【发布时间】:2018-09-06 10:38:33
【问题描述】:

Move 类的构造函数接受可以引用临时对象的右值引用。所以,我有临时对象和适当的移动构造函数,它们可以接受对临时对象的引用,但移动构造函数没有被调用。 怎么了?

    //g++  5.4.0

#include <iostream>

class foo
{
    int data;
public:
    foo(int v) : data(v) {std::cout << "foo(int)\n";}

    foo(foo&& f)
    {
        std::cout << "moved\n";
    }

    void print()
    {
        std::cout << data;
    }
};

void acceptTmp(foo f)
{
    f.print();
}

int main()
{
    foo f1 = foo(100);
    f1.print();
    acceptTmp(foo(200)); //also does not move
}

【问题讨论】:

  • @songyuanyao 我知道 c++11 没有保证复制省略,但这种行为发生在 c++11
  • 在 C++17 之前不保证,但允许。事实上,大多数体面的编译器都会应用优化。
  • @AlexF 不,移动分配也没有调用
  • 这是复制初始化 "如果 T 是一个类类型,并且 other 的类型的 cv 非限定版本是 T 或从 T 派生的类,则检查 T 的非显式构造函数,并通过重载决议选择最佳匹配。然后调用构造函数来初始化对象。” 请参阅:en.cppreference.com/w/cpp/language/copy_initialization

标签: c++ c++11 move-semantics copy-elision


【解决方案1】:

怎么了?

除了您期望调用移动构造函数之外没有任何问题。

在 C++17 之前,从抽象机器的角度来看,临时对象确实会被移动到参数中。 然而,该标准允许编译器省略移动,方法是直接构造临时对象来代替将要移动到的对象。您不能依赖移动构造函数的副作用发生。

在 C++17 之后,不涉及临时对象或移动。该标准保证参数是在适当的位置构造的。


没有移动是一件好事。移动一个对象可能比不移动它慢。

【讨论】:

    【解决方案2】:

    通常编译器通过应用as-if rule 对代码执行优化和转换。复制/移动省略是“as-if”规则的唯一例外。即使存在副作用,编译器也会优化复制和移动操作,因为复制和移动操作是有代价的。

    当然,在 C++17 之前,这取决于编译器,可能还取决于优化级别。但是从 c++17 开始,省略是有保证的。

    如果要指示编译器不执行省略,可以使用-fno-elide-constructors编译器标志。

    请参阅以下链接以了解有关复制/移动 ellison 的更多信息:

    What are copy ellision?

    【讨论】:

    • 示例代码中没有 (N)RVO。返回值优化是函数按值返回时的特定复制省略。示例中没有按值返回 foo 的函数。
    • @user2079303 -- 抱歉,我误解了这个问题。我将编辑我的答案。感谢您指出。我的答案现在可以了吗?
    • 我觉得还可以。
    猜你喜欢
    • 2020-12-30
    • 2014-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 2023-02-07
    • 2017-05-30
    • 2020-03-13
    • 1970-01-01
    相关资源
    最近更新 更多