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

Я только что прочитал о ссылках на 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 ]

0 голосов
/ 28 января 2019

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

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

emplace_back("element");

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

push_back(explicitDataType{"element"});

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

0 голосов
/ 27 января 2019

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

Программа использует изумительную библиотеку 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::

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...