Учитывая комментарии, которые я получил, я выбрал другой подход к этому ответу.Вот программа, которая использует различные способы добавления объекта в вектор.Эта программа выводит, какие именно конструкторы копирования, конструкторы перемещения, операторы копирования, операторы перемещения и деструкторы вызываются во всех случаях.
Программа использует изумительную библиотеку 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::