Created
June 21, 2019 02:45
-
-
Save zhehaowang/242e6315da279a00b82f9234e9911aef to your computer and use it in GitHub Desktop.
To demonstrate how rvalue references can be useful: in implementing moves and perfect forwarding.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <vector> | |
struct MyObject { | |
MyObject(const char * c) : content(c) { | |
std::cout << "default ctor\n"; | |
} | |
MyObject(const MyObject& rhs) : content(rhs.content) { | |
std::cout << "copy ctor\n"; | |
} | |
MyObject(MyObject&& rhs) noexcept : content(std::move(rhs.content)) { | |
std::cout << "move ctor\n"; | |
} | |
MyObject& operator=(const MyObject&) = delete; | |
MyObject& operator=(MyObject&&) = delete; | |
std::string content; | |
}; | |
std::vector<MyObject> res; | |
int make_a_copy(const MyObject& s) { | |
res.emplace_back(s); | |
return 0; | |
} | |
int make_a_move(MyObject&& s) { | |
res.emplace_back(std::move(s)); | |
return 0; | |
} | |
template <typename T> | |
int make_a_move_perfect_forwarding(T&& s) { | |
res.emplace_back(std::forward<T>(s)); | |
return 0; | |
} | |
int main() { | |
res.reserve(5); | |
MyObject s1("I am a super long string\n"); | |
make_a_copy(s1); | |
// pass by lvalue reference, we don't make a copy in passing this in, but | |
// emplace_back has to make a copy of the object. | |
make_a_copy(MyObject("I am another super long string\n")); | |
// passing an rvalue reference to make_a_copy expecting const lvalue | |
// reference. this is fine as the standard says the const reference extends | |
// the lifetime of this temporary. this wouldn't be fine if | |
// `make_a_copy` expects a non const lvalue reference. | |
// | |
// emplace_back also has to make a copy in this case, since 's' in the scope | |
// of `make_a_copy` is an lvalue. | |
// | |
// note that what we are doing here doesn't really need to a copy: emplace | |
// could have just moved the temporary we have here into the vector, but | |
// all emplace sees is an lvalue so it cannot really do anything. | |
make_a_copy("I am again a super long string\n"); | |
// again emplace_back has to make a copy. only difference here's that we | |
// implicitly convert this literal to a MyObject temporary. | |
// | |
// note that what we are doing here doesn't even need a move: emplace could | |
// have just constructed MyObject in-place. | |
make_a_move(MyObject("I am once more a super long string\n")); | |
// emplace does not copy in this case, it moves instead. we save the cost of | |
// copying. | |
make_a_move_perfect_forwarding("I am finally a super long string\n"); | |
// emplace does not even move, it constructs in-place. we save the cost of | |
// copying / moving MyObject around completely | |
for (const auto& elem: res) { | |
std::cout << elem.content; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment