Rvalue Reference
Background
Rvalue reference:
- An rvalue reference is a reference that will bind only to a temporary object.
std::move, std::forward
- std::move
* takes an object and allows you to treat it as a temporary (an rvalue)
- std::forward
* has a single use case: to cast a templated function parameter (inside the function) to the value category (lvalue or rvalue) the caller used to pass it. * This allows rvalue arguments to be passed on as rvalues, and lvalues to be passed on as lvalues, a scheme called "perfect forwarding."
operator =
- default implementation for operator= is copy
* it copies each member, it’s calling the constructor that accepting the type on the right of the operator= * for example for base_string, the 7th constructor: * basic_string( const basic_string& other ); * Copy constructor. Constructs the string with the copy of the contents of other.
- Thus in order for the the class type to accept rvalue reference, it should also have a constructor accepting a rvalue reference
* and the constructor should be implemented by std::move * see the 8th constructor
move constructor
- Move constructors typically “steal” the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, I/O streams, running threads, etc.) rather than make copies of them
Incentive
Move semantics allows you to avoid unnecessary copies when working with temporary objects that are about to evaporate, and whose resources can safely be taken from that temporary object and used by another
If we are creating a temporary objects, and we know that it will only be used for the constructor, specifically it will be passed into the constructor as a class member. Then it’s better for the constructor to directly make the class member pointing to the value of that temporary objects.
class Type{
public Type(string str){
str = str; // it will definitely be copied
}
public Type(string& str_){
str = str_; // it will also be copied, see the reference constructor (7th constructor) of base_string
}
public Type(string&& str_){
str = std::move(str_); // first, std::move will ensure that str_ is accepted as a rvalue. Then this will call the rvalue constructor (also called move constructor) of base_string
}
public string& str;
}
But if we are passing in the parameter as an object or reference.
- in object’s case, we know that it will be copied
- in reference’s case, we also know that it’s a copy constructor (explained above in the operator=)
thus in either case, it will be copied, this is not good for performance.
With rvalue reference as a parameter, and std::move/forward, we can let the class member directly pointing to the temporary object.
class Type{
public Type(string&& str_){
// first, std::move will ensure that str_ is accepted as a rvalue.
// Then this will call the rvalue constructor (also called move constructor) of base_string
str = std::move(str_);
}
public string& str;
}
Case Study
Case 1
In Mesos project, we have this usage:
template
inline mesos::v1::Resource::DiskInfo createDiskInfo(Args&&… args)
{
return common::createDiskInfo
std::forward
}
It’s accepting Args, the parameter pack as a rvalue reference. The reason is that: our usage for these functions looks like this
Resource volume1 = Resources::parse(“disk”, “128”, “role1”).get();
volume1.mutable_disk()->CopyFrom(createDiskInfo(“id1”, “path1”));
where the parameters are strings and they are created specifically for the construction of the DiskInfo, thus in order to avoid copying the value, we accept rvalue reference for the parameter of the DiskInfo constructor, then it will call the move constructor of base_string, thus copies are avoided
Case 2
In the case below, the authorizer.get()->getObjectApprover return a Owned
Future
const Option
const Option
const authorization::Action& action)
{
if (authorizer.isNone()) {
return Owned
new AuthorizationAcceptor(Owned
new AcceptingObjectApprover())));
}
const Option
authorization::createSubject(principal);
return authorizer.get()->getObjectApprover(subject, action)
.then(= {
return Owned
new AuthorizationAcceptor(approver));
});
}
References
- http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html
- http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html
- http://en.cppreference.com/w/cpp/string/basic_string/basic_string
- https://www.chromium.org/rvalue-references
- http://thbecker.net/articles/rvalue_references/section_04.html