#include #include #include #include #include #include using namespace fmt; // Some heavy object struct A { A() = default; A(int val) : val(val) { std::cout << "called constructor with: " << val << std::endl; } A(A const& other) { std::cout << "calling copy(A const& other): " << val << std::endl;; } A(A&& other) { std::cout << "calling move(A&& other): " << val << std::endl;; } A& operator=(A&& other) { std::cout << "calling move(A&& other)=: " << val << std::endl;; return *this; } A& operator=(A const& other) { std::cout << "calling copy(A const& other)=: " << val << std::endl;; return *this; } ~A() = default; int val{}; }; TEST_CASE("emplace move tests", "[emplace]") { A a{10}; std::vector test; test.reserve(10); // to prevent vector resizing and creating new objects on the way std::cout << "===== Emplacing Start =====\n"; // pass by l-value and will call copy constructor since it'll match // A(A const&) std::cout << "== 1. Emplace: Calling copy constructor \n"; test.emplace_back(a); // pass by r-value and will call move constructor since it'll match // A(A&&) std::cout << "== 2. Emplace: Calling move constructor \n"; test.emplace_back(std::move(a)); std::cout << "== 3. Emplace: Calling move constructor without direct constructor\n"; test.emplace_back(100); // pass by pr-value (pure r-value which is those value that has not come to an existance yet) // and will call move constructor since it'll match A(A&&). // "copy-elision" could be applied here but I don't know why compilers // refused to do it. Maybe how vectors are implemented and you need // to put the value in a slot so the compiler had to call the move constructor std::cout << "== 4. Emplace: Calling move constructor\n"; test.emplace_back(A{}); } TEST_CASE("pushback move tests", "[push_back]") { std::cout << "\n\n!!!!!!!!!! PUSH BACK alternative !!!!!!!!!!\n"; A a{20}; std::vector test; test.reserve(10); // to prevent vector resizing and creating new objects on the way std::cout << "===== Push Back Start =====\n"; // pass by l-value and will call copy constructor since it'll match // A(A const&) std::cout << "== 1. Push Back: Calling copy constructor \n"; test.push_back(a); // pass by r-value and will call move constructor since it'll match // A(A&&) std::cout << "== 2. Push Back: Calling move constructor \n"; test.push_back(std::move(a)); std::cout << "== 3. Push Back: Calling move constructor without direct constructor\n"; test.push_back(200); // pass by pr-value (pure r-value which is those value that has not come to an existance yet) // and will call move constructor since it'll match A(A&&). // "copy-elision" could be applied here but I don't know why compilers // refused to do it. Maybe how vectors are implemented and you need // to put the value in a slot so the compiler had to call the move constructor std::cout << "== 4. Push Back: Calling move constructor\n"; test.push_back(A{}); } TEST_CASE("proof you don't need emplace or std::move", "[proof]") { }