【问题标题】:Why are constructed objects, in tuple initialization, copied?为什么在元组初始化中复制构造的对象?
【发布时间】:2017-04-17 19:26:41
【问题描述】:

我有一种情况,我无法解决。我定义了一个不可复制的结构,并希望在一个元组中就地构造它。如果我这样做,它就会被复制。我以为问题可能出在std::make_tuple,但事实并非如此。

如果我构造对象,然后在元组中移动它,事情就会按预期工作。

演示(我使用std::exit来防止正常破坏的输出)。

#include <tuple>
#include <iostream>
#include <cstdlib>

struct MoveMe {
    MoveMe(size_t s) : size(s) {}
    MoveMe(MoveMe&&) = default;
    MoveMe(const MoveMe&) = delete;

    MoveMe& operator=(MoveMe&&) = default;
    MoveMe& operator=(const MoveMe&) = delete;

    ~MoveMe() {
        std::cout << "Destroyed" << std::endl;
    }

    size_t size = 0;
};

int main(int, char**) {
    std::cout << "Constructed in-place." << std::endl;
    auto tuple = std::make_tuple(MoveMe{10});

    std::cout << std::endl << "Other tests." << std::endl;
    std::tuple<MoveMe> tuple2 = std::tuple<MoveMe>(MoveMe{10});

    std::cout << std::endl << "Moved." << std::endl;
    MoveMe obj{10};
    auto tuple3 = std::make_tuple(std::move(obj));

    std::exit(0);
    // return 0;
}

输出

就地建造。

销毁

其他测试。

销毁

搬家了。

有什么想法吗?我对右值的理解是基本的,所以我的猜测是我遗漏了一些明显的东西。谢谢。

【问题讨论】:

  • 被复制是什么意思?
  • 调用了析构函数,所以它被复制到元组中。没有?
  • 您似乎对~MoveMe() 的调用感到困惑。当有移动操作时,被移动的变量仍然存在,它仍然必须被销毁;它可能仍包含一些其他必须正确发布的数据。您正在创建一个临时的并从中移动。在表达式完成并将其内容移入元组后,该临时对象将立即被销毁。

标签: c++ copy tuples move rvalue


【解决方案1】:

它没有被复制它仍然被移动。

在您的情况下,您正在创建一个临时 (MoveMe{10}),然后用于在元组中移动构造 MoveMe 的实例。元组中MoveMe的实例被移动构造后,被移动的临时对象被销毁。

可以通过转发参数直接在元组中构造MoveMe对象

std::cout << "Directly Constructed" << std::endl;
auto tuple = std::tuple<MoveMe>(10);

这不会导致临时创建然后销毁。

【讨论】:

  • 好的,正如 cmets 中所说,我肯定很困惑 :) 创建对象不直接返回右值吗?
  • 它是一个右值,但仍然是一个有效的对象。当您移动构造时,您需要对象的两个实例。您要移动的对象和您要移动的对象。在您的情况下,您要从中移动的对象 (MoveMe{10}) 是一个临时右值,一旦控制离开范围(定义它的语句)就会被破坏。
  • 哇,那是一个“令人震惊”的时刻。我想我必须学习更多的基础知识。感谢您解释问题。
猜你喜欢
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
  • 2021-10-23
  • 2011-03-09
  • 2021-09-10
  • 1970-01-01
  • 2021-08-05
  • 2010-10-18
相关资源
最近更新 更多