Должен ли я изменить этот код, который использует push_back для использования std::move?

Я только что прочитал о ссылках rvalue, и ниже приведен код, на который я ссылаюсь

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, где все, что нам нужно, это данные в контейнере, а не переменные.

2 ответа

Учитывая комментарии, которые я получил, я выбрал другой подход к этому ответу. Вот программа, которая использует различные способы добавления объекта в вектор. Эта программа выводит, какие именно конструкторы копирования, конструкторы перемещения, операторы копирования, операторы перемещения и деструкторы вызываются во всех случаях.

Программа использует чудесную библиотеку fmt. А также fmt::print делает именно то, что вы думаете, что делает. Я должен, возможно, использовать ::fmt, Имейте в виду, что перемещение от объекта вообще оставляет его в неопределенном (заметьте, не совпадает с неопределенным) состоянии. Конечно, для классов, которые вы пишете сами, вы точно знаете, в каком состоянии они находятся. Но для стандартных библиотечных классов или классов, написанных другими людьми, вы этого не делаете. По-видимому, для стандартных библиотечных классов вам гарантировано, что если вы сделаете что-то, чтобы установить состояние на что-то известное, то объект действительно изменится на это состояние.

Лично я бы относился к объекту так, как будто единственная допустимая операция над ним после того, как вы от него ушли, - это вызвать его деструктор. Но я вижу случаи, когда вы можете просто захотеть повторно использовать хранилище каким-то образом.

Вот программа:

#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::

Q: что следует использовать?

// emplace_back создает элементы на месте.

emplace_back("element");

// push_back создаст новый объект и затем скопирует (или переместит) его значение аргументов.

push_back(explicitDataType{"element"});

Так что здесь вы должны использовать emplace_back() вместо std::move(),

Другие вопросы по тегам