Skip to content

Instantly share code, notes, and snippets.

@zhehaowang
Created June 21, 2019 02:45
Show Gist options
  • Save zhehaowang/242e6315da279a00b82f9234e9911aef to your computer and use it in GitHub Desktop.
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.
#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