【问题标题】:C++ move(): what's left in the vector?C++ move():向量中还剩下什么?
【发布时间】:2020-04-28 15:45:32
【问题描述】:

我有一段代码,在vector 中,元素是成对的intstring。然后我想将所有元素从vector 移动到unordered_map<int, string>

#include <algorithm>
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <vector>
using namespace std;

template <typename C>
void print(const C& container) {
    for (const auto& ele : container) {
        cout << "(" << ele.first << ", " << ele.second << "), ";
    }
    cout << endl;
}

int main() {
    vector<pair<int, string>> v {
        {1, "one"},
        {2, "two"},
        {3, "three"},
        {4, "four"},
        {5, "five"}
    };
    unordered_map<int, string> uMap;

    move(begin(v), end(v), inserter(uMap, begin(uMap)));

    cout << "In unordered_map:" << endl;
    print(uMap);
    cout << endl << "In vector:" << endl;
    print(v);

    return 0;
}

我不明白的是结果:

In unordered_map:
(5, five), (4, four), (3, three), (2, two), (1, one), 
In vector:
(1, ), (2, ), (3, ), (4, ), (5, ),

为什么那些整数留在vector 中?我以为move() 函数会将所有元素从vector 移动到unordered_map,这样vector 中就不会留下任何东西?

【问题讨论】:

    标签: c++ vector move unordered-map


    【解决方案1】:

    来自cppreference

    将范围 [first, last) 中的元素移动到从 d_first 开始的另一个范围,从 first 开始一直到 last - 1。在此操作之后,移动范围中的元素仍将包含有效值适当的类型,但不一定与移动前的值相同。

    因为算法在迭代器上工作,所以它实际上无法从向量中删除元素。它们仍然存在,并且可以具有与以前相同的值(但不一定)。

    而且字符串仍然存在于向量中。从std::string 移动后,它处于有效但未指定的状态。在这种情况下,字符串为空。

    【讨论】:

    • 谢谢@idclev 那为什么对中的字符串部分从vector中删除了?
    • @dxfkgdkjfgbizldu 虽然允许任何状态,但通常最多有两种可能性:移动的值不变,或者它们处于某种“空”状态。
    【解决方案2】:

    这里的“移动”并不是真正的意思。

    是的,这令人困惑。

    地图中的新元素将由向量中的元素移动构造。这可能涉及从向量中的元素窃取资源(特别是,动态分配的字符串数据现在将属于新元素,并与旧元素分离)。

    但这实际上并没有删除原始元素。他们还在那里,处于搬离状态。您需要自己 clear() 向量。

    quote Eljay

    std::move 在某些方面是一个不幸的术语。但它比std::suck_out_the_guts_and_transplant_them_into_another_object_maybe短得多。

    【讨论】:

      【解决方案3】:

      通俗地说,对移出对象的唯一要求是它可以在以后安全地销毁。对于int,最好的办法就是什么都不做。移动不会破坏对象,也不会将其从容器中移除。对象仍在向量中,只是它们现在处于移动状态,对于int,恰好和以前一样。

      【讨论】:

      • 谢谢@alain 那为什么对中的字符串部分从vector中删除了?
      • 字符串有一个内部缓冲区,它被移动到另一个对象。
      • 我们可以说 move() 函数仍然有未定义的行为,因为它处理 pair 的方式似乎是出乎意料的,并且不符合从源容器中销毁元素的目标从而降低内存成本?
      • @dxfkgdkjfgbizldu • std::move 在某些方面是一个不幸的术语。但它比std::suck_out_the_guts_and_transplant_them_into_another_object_maybe 短得多。
      • @dxfkgdkjfgbizldu 小心“未定义行为”与“未指定”。粗略地说,“未定义”是邪恶的,不能出现在有效的 c++ 程序中,“未指定”只是意味着它可以是任何东西。同样对于int,它已经很好地定义了会发生什么。对于无法移动的对象,移动只是一个副本
      【解决方案4】:

      std::move 实际上并没有移动任何东西。它只是对右值进行强制转换,并告诉编译器您不再关心该对象会发生什么。在 int 的情况下,编译器决定将其复制为最有效的方式。

      您可以在此处阅读有关 c++ 移动语义的更多信息:C++ move semantics

      【讨论】:

      • “最有效的方法” 这是唯一的方法。没有其他方式存在/有意义。没有间接,没有移动。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-09
      • 2022-01-14
      • 1970-01-01
      • 2018-06-27
      • 1970-01-01
      • 2015-05-10
      • 2020-08-06
      相关资源
      最近更新 更多