首页 > 解决方案 > 我应该更改使用 push_back 的代码以使用 std::move 吗?

问题描述

我刚刚阅读了关于右值引用的内容,下面是我所指的代码

vector<string> v;
string s = "hello";   

v.push_back(s); 
cout << s << endl;
cout << v[0] << endl;
return 0

我的问题是,到目前为止,每当我看到对象(或字符串)的向量时,我大多会看到像上面那样完成插入操作。相反,如果我这样做了v.push_back(std::move(s)),我就不会不必要地创建重复的对象。

这是否是向 STL 添加对象的正确方法,我们只关心容器中的数据而不是其他变量。

标签: c++stlstdmove

解决方案


鉴于我得到的评论,我决定采用不同的方法来回答这个问题。这是一个使用各种方法将对象添加到向量的程序。该程序准确打印出在所有情况下调用了哪些复制构造函数、移动构造函数、复制运算符、移动运算符和析构函数。

该程序使用了奇妙的fmt 库。并且fmt::print完全按照你的想法去做。也许我应该使用::fmt. 请记住,从对象移动通常会使其处于未指定(注意,与undefined不同)状态。当然,对于您自己编写的类,您确切地知道它处于什么状态。但是对于标准库类或其他人编写的类,您不知道。显然,对于标准库类,您可以保证,如果您将状态设置为已知的状态,则该对象确实会更改为该状态。

就个人而言,我只是将对象视为从它移出后对其进行的唯一有效操作是调用其析构函数。但是我可以看到您可能只是想以某种方式重新使用存储的情况。

这是程序:

#include <fmt/core.h> // fmt
#include <vector>  // vector
#include <utility> // move

class TestClass {
 public:
    TestClass(int a, int b) {
        fmt::print("TestClass{{{}, {}}}\n", a, b);
    }
    TestClass(TestClass const &) noexcept {
        fmt::print("TestClass{{TestClass const &}}\n");
    }
    TestClass(TestClass &&) noexcept {
        fmt::print("TestClass{{TestClass &&}}\n");
    }
    TestClass const &operator =(TestClass const &) noexcept {
        fmt::print("=(TestClass const &)\n");
        return *this;
    }
    TestClass const &operator =(TestClass &&) noexcept {
        fmt::print("=(TestClass &&)\n");
        return *this;
    }
    ~TestClass() noexcept {
        fmt::print("~TestClass()\n");
    }
};

int main()
{
   ::std::vector<TestClass> v;
   // Reserve necessary space so movements of vector elements doesn't clutter up
   // the output.
   v.reserve(6);
   fmt::print("Constructing initial\n");
   TestClass o{1, 2};

   fmt::print("\bv.push_back(o)\n");
   v.push_back(o);

   fmt::print("\nv.push_back(::std::move(o))\n");
   v.push_back(::std::move(o));

   fmt::print("\nv.push_back(TestClass{{3, 4}})\n");
   v.push_back(TestClass{3, 4});

   fmt::print("\nv.emplace_back(5, 6)\n");
   v.emplace_back(5, 6);

   fmt::print("\nv.emplace_back(::std::move(o))\n");
   v.emplace_back(::std::move(o));

   fmt::print("\nv.emplace_back(TestClass{{5, 6}})\n");
   v.emplace_back(TestClass{5, 6});

   fmt::print("\nHere H\n");
}

这是程序的输出:

Constructing initial
TestClass{1, 2}
v.push_back(o)
TestClass{TestClass const &}

v.push_back(::std::move(o))
TestClass{TestClass &&}

v.push_back(TestClass{3, 4})
TestClass{3, 4}
TestClass{TestClass &&}
~TestClass()

v.emplace_back(5, 6)
TestClass{5, 6}

v.emplace_back(::std::move(o))
TestClass{TestClass &&}

v.emplace_back(TestClass{5, 6})
TestClass{5, 6}
TestClass{TestClass &&}
~TestClass()

Here H
~TestClass()
~TestClass()
~TestClass()
~TestClass()
~TestClass()
~TestClass()
~TestClass()

我会说这个程序完全符合我的预期,并且该输出(AFAIK)与我之前在这里得到的答案一致。


为什么我使用::std::而不是std::


推荐阅读