Why not to accept std::unique_ptr by rvalue reference? - c++

Can somebody explain why everybody passes std::unique_ptr by value instead of by rvalue reference?
From what I've observed, this required an additional move constructor to be invoked.
Here's an example of a class holding a "pointer". It takes 3 move-ctor calls to take it by value, versus 2 calls to take it by reference:
#include <memory>
#include <iostream>
class pointer {
public:
pointer()
{ std::cerr << "ctor" << std::endl; }
pointer(const pointer&)
{ std::cerr << "copy-ctor" << std::endl; }
pointer& operator=(const pointer&)
{ std::cerr << "copy-assignment" << std::endl; return *this; }
pointer(pointer&&)
{ std::cerr << "move-ctor" << std::endl; }
pointer& operator=(pointer&&)
{ std::cerr << "move-assignment" << std::endl; return *this; }
~pointer()
{ std::cerr << "dtor" << std::endl; }
};
class A {
public:
// V1
A(pointer _ptr) : ptr(std::move(_ptr)) {}
// V2
A(pointer&& _ptr) : ptr(std::move(_ptr)) {}
private:
pointer ptr;
};
int main() {
// Three calls to move-ctor versus two calls if pass by rvalue reference
auto ptr = pointer();
A a(std::move(ptr));
// Two calls to move-ctor always
A a(pointer{});
}

Passing a unique_ptr by reference, rvalue or otherwise, doesn't actual move anything, so you can't know by just looking at the function declaration if a move will happen.
Passing a unique_ptr by value on the other hand guarantees that the passed in pointer will be moved from, so without even have to look at the documentation you know calling that function releases you from the pointers' ownership.

For the same reason people pass int instead of const int&.
std::unique_ptr is just an RAII wrapper around a single pointer value, so moving it is just copying a single register width value, then zeroing the source. That's so trivial there's no real benefit to avoiding the move. After all, the cost to pass the reference (when not inlined) is the cost of passing a pointer too, so passing by reference can be less efficient (because if not inlined, it has to follow the reference to the real memory, then pull out the value from there; the top of the stack is likely in L1 cache, who knows if the place it's stored is?).
In practice, much of this will be inlined with optimizations enabled, and both approaches would get the same result. Passing by value is a good default when there's no benefit to passing by reference, so why not do it that way?

why everybody passes the std::unique_ptr by value instead of rvalue reference?
It may be more common, but it's not "everybody".
The drawback of std::unique_ptr&& parameter is that it doesn't explicitly communicate to the caller whether the pointer will be moved from or not. It might always move, or it might depend on some condition. You would have to know the implementation or at least API documentation to know for sure. The corresponding benefit of std::unique_ptr parameter is that it alone tells the reader of the declaration that the function will take ownership of the pointer. For this reason, it may be a good choice to use std::unique_ptr parameter and probably part of the reason why it's more common.
The benefit of std::unique_ptr&& is avoiding the extra move. However, moving of a std::unique_ptr is a very fast operation. It's insignificant compared for example to the memory allocation itself. In most cases, it simply doesn't matter.
The difference between the two is fairly subtle. std::unique_ptr&& parameter may be considered in a case where you've measured the move to have significant cost. Which is not very common. Or in cases where your API may be used in cases where that cost could be significant. It's hard to prove that this won't ever happen if you're writing a public API, so it is a more likely argument to use.

Related

Deep-copy of struct with reference member in C++17

I'm still fairly new to C++ and am confused about references and move semantics. For a compiler I'm writing that generates C++17 code, I need to be able to have structs with fields that are other structs. Since the struct definitions will be generated from the user's code in the other language, they could potentially be very large, so I'm storing the inner struct as a reference. This is also necessary to deal with incomplete types that are declared at the beginning but defined later, which may happen in the generated code. (I avoided using pointers because adding * all over the place for dereferencing makes the code generation less straightforward.)
The language I'm compiling from has no aliasing, so something like Outer b = a should always be a "deep-copy". So in this case, b.inner should be a copy of a.inner and not a reference to it. But I can't figure out how to setup the constructors to create the deep-copy behavior in C++. I tried many different configurations of the constructors for Outer, and I tried both Inner& and Inner&& for storing inner.
Here is a mock example of how the generated code would look:
#include <iostream>
template<typename T>
T copy(T a) {
return a;
}
struct Inner;
struct Outer {
Inner&& inner;
Outer(Inner&& a);
Outer(Outer& a);
};
struct Inner {
int v;
};
Outer::Outer(Inner&& a) : inner(std::move(a)) {
std::cout << " -- Constructor 1 --" << std::endl;
}
// Copy the insides of the original object, then move that rvalue to the new object?
Outer::Outer(Outer& a) : inner(std::move(copy(a.inner))) {
std::cout << " -- Constructor 2 --" << std::endl;
}
int main() {
Outer a = {Inner {30}};
std::cout << a.inner.v << std::endl; // Should be: 30
a.inner.v += 1;
std::cout << a.inner.v << std::endl; // Should be: 31
Outer b = a; // Copy a to b
std::cout << a.inner.v << std::endl; // Should be: 31
std::cout << b.inner.v << std::endl; // Should be: 31
b.inner.v += 1;
std::cout << a.inner.v << std::endl; // Should be: 31
std::cout << b.inner.v << std::endl; // Should be: 32
return 0;
}
And this is what it currently outputs (it may vary by implementation):
-- Constructor 1 --
30
31
-- Constructor 2 --
297374876
32574
297374876
32574
Clearly this output is incorrect, and I think I must have a dangling reference somewhere among other things. How should I setup Outer to get the proper behavior here?
References in C++ are (almost always) non owning aliases.
You do not want a non owning alias.
Thus, do not use references.
You could have an owning (smart) pointer and a reference alias to make some code generation easier. Do not do this. The result of doing it is a class with mixed semantics; there is no coherant sensible operator= and copy/move constructors you can write in that case.
My advice would be to:
Write a value_ptr that inherits from unique_ptr but copies on assignment.
then either:
Generate code with ->
or
Add a helper method that returns *ptr reference, and generate code that does method().
(I avoided using pointers because adding * all over the place for dereferencing makes the code generation less straightforward.)
Don't let your desired interface interfere so much with your implementation. Separation of interface and implementation is a powerful tool.
Your goal is a deep copy. Your temporaries will not live long enough. Something has to own the copied data so it both lives long enough (no dangling references) and does not live too long (no leaked memory). A reference does not own its data. Since the data will not be directly part of your structure, you need a pointer with ownership semantics.
This does not mean that the code has to add de-referencing "all over the place". To aid your interface, you could have a reference to the object owned by the pointer. Normally this would be wasted space, but it might serve a purpose in your project, assuming your assessment about code generation is accurate.
Example:
struct Outer {
// Order matters here! The pointer must be declared before the reference!
// (This should be less of a problem for generated code than it can be for
// code edited by human programmers.)
const std::unique_ptr<Inner> inner_ptr;
Inner & inner;
// The idea is that `inner` refers to `*inner_ptr`, and the `const` on
// `inner_ptr` will prevent `inner` from becoming a dangling reference.
// Copy constructor
Outer(const Outer& src) :
inner_ptr(std::make_unique<Inner>(src.inner)), // Make a copy
inner(*inner_ptr) // Reference to the copy
{}
// The compiler-generated assignment operator will be deleted because
// of the reference member, just as in the question's code
// (so having it deleted because of the `unique_ptr` is not an issue).
// However, to make this explicit:
Outer& operator=(const Outer&) = delete;
};
With the above setup, you could still access the members of the inner data via syntax like object.inner.field. While this is redundant with access via the object.inner_ptr->field syntax, you indicated that you have established a need for the former syntax.
For the benefit of future readers:
This approach has drawbacks that would normally cause me to recommend against it. It is a judgement call as to which drawbacks are greater – those in this approach or the "less straightforward" code generation. Sometimes machine-generated code needs a bit of inefficiency to ensure that corner cases function correctly. So this might be acceptable in this particular case.
If I may stray a bit from your desired syntax, a neater option would be to have an accessor function. Whether or not this is applicable in your situation depends on details that are appropriately out-of-scope for this question. It might be worth considering.
Instead of wasting space by storing a reference in the structure, you could generate the reference as needed via a member function. This has the side-effect of removing the need to mark the pointer const.
struct Outer {
// Note the lack of restrictions imposed on the data.
// All that might be needed is an assertion that inner_ptr will never be null.
std::unique_ptr<Inner> inner_ptr;
// Here, `inner` will be a member function instead of member data.
Inner & inner() { return *inner_ptr; }
// And a const version for good measure.
const Inner & inner() const { return *inner_ptr; }
// Copy constructor
Outer(const Outer& src) :
inner_ptr(std::make_unique<Inner>(src.inner())) // Make a copy
{}
// With this setup, the compiler-generated copy assignment
// operator is still deleted because of the `unique_ptr`.
// However, a compiler-generated *move* assignment is
// available if you specifically request it.
Outer& operator=(const Outer&) = delete;
Outer& operator=(Outer &&) = default;
};
With this setup, access to the members of the inner data could be done via syntax like object.inner().field. I don't know if the extra parentheses will cause the same issues as the asterisks would.
Deep copying only makes sense when the class has ownership. A reference isn't generally used for owernship.
Clearly this output is incorrect, and I think I must have a dangling reference somewhere among other things
You've guessed correctly. In the declaration: Outer a = {Inner {30}}; The instance of Inner is a temporary object and its lifetime extends until the end of that declaration. After that, the reference member is left dangling.
so I'm storing the inner struct as a reference
A reference doesn't store an object. A reference refers to an object that is stored somewhere else.
How should I setup Outer to get the proper behavior here?
It seems that a smart pointer might be useful for your use case:
struct Outer {
std::unique_ptr<Inner> inner;
};
You'll need to define a deep copy constructor and assignment operator though.

std::move in initializer lists

I often see the following idiom in production code: A value argument (like a shared pointer) is handed into a constructor and shall be copied once. To ensure this, the argument is wrapped into a std::move application. Hating boilerplate code and formal noise I wondered if this is actually necessary. If I remove the application, at least gcc 7 outputs some different assembly.
#include <memory>
class A
{
std::shared_ptr<int> p;
public:
A(std::shared_ptr<int> p) : p(std::move(p)) {} //here replace with p(p)
int get() { return *p; }
};
int f()
{
auto p = std::make_shared<int>(42);
A a(p);
return a.get();
}
Compiler Explorer shows you the difference. While I am not certain what is the most efficient approach here, I wonder if there is an optimization that allows to treat p as a rvalue reference in that particular location? It certainly is a named entity, but that entity is "dead" after that location anyway.
Is it valid to treat a "dead" variable as a rvalue reference? If not, why?
In the body of the constructor, there are two p objects, the ctor argument and this->p. Without the std::move, they're identical. That of course means the ownership is shared between the two pointers. This must be achieved in a thread-safe way, and is expensive.
But optimizing this out is quite hard. A compiler can't generally deduce that ownership is redundant. By writing std::move yourself, you make it unambiguously clear that the ctor argument p does not need to retain ownership.

Is pass by value that much faster?

I've heard that you should always prefer "pass by value" in C++11 because of the introduction of move semantics. I wanted to see what the hype was all about and constructed a test case. First my class:
struct MyClass {
MyClass() { }
MyClass(const MyClass&) { std::cout << "Copy construct" << std::endl; }
MyClass(MyClass&&) { std::cout << "Move construct" << std::endl; }
~MyClass() { }
};
And the test harness:
class Test
{
public:
void pass_by_lvalue_ref(const MyClass& myClass)
{
_MyClass.push_back(myClass);
}
void pass_by_rvalue_ref(MyClass&& myClass)
{
_MyClass.push_back(std::move(myClass));
}
void pass_by_value(MyClass myClass)
{
_MyClass.push_back(std::move(myClass));
}
private:
std::vector<MyClass> _MyClass;
};
Presumably, pass_by_value should outperform pass_by_lvalue_ref and pass_by_rvalue_ref (together, not separately).
int main()
{
MyClass myClass;
Test Test;
std::cout << "--lvalue_ref--\n";
Test.pass_by_lvalue_ref(myClass);
std::cout << "--rvalue_ref--\n";
Test.pass_by_rvalue_ref(MyClass{});
std::cout << "--value - lvalue--\n";
Test.pass_by_value(myClass);
std::cout << "--value - rvalue--\n";
Test.pass_by_value(MyClass{});
}
This is my output on GCC 4.9.2 with -O2:
--lvalue_ref--
Copy construct
--rvalue_ref--
Move construct
Copy construct
--value - lvalue--
Copy construct
Move construct
Copy construct
Copy construct
--value - rvalue--
Move construct
As you can see, the non-pass_by_value functions requires a total of 2 copy constructs and 1 move construct. The pass_by_value function requires a total of 3 copy constructs and 2 move constructs. It looks like that, as expected, the object is going to be copied anyway, so why does everyone say pass by value?
First, your reporting is entirely flawed. Each of your functions pushes back to the same vector. When that vector runs out of capacity (which depends upon how many items you've inserted so far), it is going to trigger a re-allocation which will require more moves and/or copies than an insertion which doesn't trigger an allocation.
Second, std::vector::push_back has a strong exception safety guarantee. So if your move constructor is not noexcept, it will not use it (unless the class is non-copyable). It will use the copy constructor instead.
Third,
I've heard that you should always prefer "pass by value" in C++11
because of the introduction of move semantics.
I'm pretty sure you didn't hear that from any reputable source. Or are actually inappropriately paraphrasing what was actually said. But I don't have the source of the quote. What is usually advised is actually that if you are going to copy your arguments in your function anyway, don't. Just do it in the parameter list (via pass by value). This will allow your function to move r-value arguments straight to their destination. When you pass l-values, they will be copied, but you were going to do that anyway.
If you are going to make an internal copy, then passing by value will do exactly one move construct more than the pair of overloads (pass by rvalue ref)+(pass by const lvalue ref).
If move construct is cheap, this is a small amount of runtime overhead in exchange for less compile time and code maintenance overhead.
The idiom is "Want speed? Making a copy anyhow? Pass by value, instead of by const lvalue reference." in reality.
Finally, your benchmark is flawed as you failed to reserve(enough) before your push backs. Reallocation can cause extra operations. Oh, and make your move constructor noexcept, as conforming libraries will prefer a copy to a move if move can throw in many situations.

How do I utilize move semantics when returning a member variable?

I'm implementing a factory class which builds a vector of uint8_t. I want to be able to utilize move semantics when returning the resulting vector. This seems to work but I'm not confident this is the correct way of accomplishing what I want.
I have seen quite a few examples of how a returned automatic variable will be regarded as an rvalue and use the move constructor of the calling code, but in my example, the returned object is a member. I know the member will loose its contents if the caller puts the return value into a move constructor - and this is just what I want.
I have written it something like this:
#include <cstdint>
#include <iostream>
#include <vector>
class Factory
{
public:
std::vector<uint8_t> _data;
Factory(std::size_t size) :
_data(size, 0)
{
}
void buildContent(int param)
{
// perform operations on the contents of _data
}
std::vector<uint8_t> && data()
{
return std::move(_data);
}
};
int main()
{
Factory factory(42);
factory.buildContent(1);
std::vector<uint8_t> temp(factory.data());
std::cout << "temp has " << temp.size() << " elements" << std::endl;
std::cout << "factory._data has " << factory._data.size() << " elements" << std::endl;
return 0;
}
Edit:
Oh, and the example code outputs the following:
temp has 42 elements
factory._data has 0 elements
First of all, you have to decide what you want. Do you really want to suck data out of your instance? If so, what you have achieves that fine. On the other hand, it looks quite unsafe. What you could do is use reference qualifiers to enforce that you only return an rvalue reference when the instance itself is an rvalue reference:
std::vector<uint8_t> && data() && // called on rvalue
{
return std::move(_data);
}
// return lvalue ref or value
std::vector<uint8_t>& data() & // called on lvalue
{
return _data;
}
In the end, it all depends on which problem you are trying to solve, which is not apparent from your question.
If your compiler has rvalue references to this (&& after methods), you might want to use that. See #juanchopanza's answer.
If you don't, you first want to make sure that data() makes it clear that you are moving. There are a few ways to do this.
First, non-member methods (friends) can override on &&. So you can get this syntax:
std::vector<uint8_t> temp(get_data( std::move(factory) );
where get_data has && and & overloads on your factory type, and either moves or not based off it.
Next, you want to return a std::vector<uint8_t> instead of a `std::vector<uint8_t>&& for lifetime extension issues. The runtime cost is somewhere between zero and small, but the bugs eliminated are worthwhile.
If create_factory returns a Factory object, then if we do this:
for( uint8_t x : get_data( create_factory() ) )
the get_data that returns a && doesn't work, while the one that returns a temporary works flawlessly.
What is going on? Well, ranged-based for loops are defined as binding the thing you are iterating over to a reference. A temporary bound to a reference has its lifetime extended: a reference bound to a reference has no lifetime extension. The create_factory function's return value's lifetime is not extended in either case.
With the && case, the reference to vector is left dangling. With the return-temporary case, the factory's vector is moved into the temporary, then that temporaries lifetime is extended.
In short, returning && references is very rarely a good idea.
How about hiding the assignment operator in your vector and only implementing move assignment operator (essentially disallowing copying - if that's what you want).
So that this:
std::vector<uint8_t> temp(factory.data());
will not compile unless you change it to this :
std::vector<uint8_t> temp(std::move(factory));

Avoiding need for #define with expression templates

With the following code, "hello2" is not displayed as the temporary string created on Line 3 dies before Line 4 is executed. Using a #define as on Line 1 avoids this issue, but is there a way to avoid this issue without using #define? (C++11 code is okay)
#include <iostream>
#include <string>
class C
{
public:
C(const std::string& p_s) : s(p_s) {}
const std::string& s;
};
int main()
{
#define x1 C(std::string("hello1")) // Line 1
std::cout << x1.s << std::endl; // Line 2
const C& x2 = C(std::string("hello2")); // Line 3
std::cout << x2.s << std::endl; // Line 4
}
Clarification:
Note that I believe Boost uBLAS stores references, this is why I don't want to store a copy. If you suggest that I store by value, please explain why Boost uBLAS is wrong and storing by value will not affect performance.
Expression templates that do store by reference typically do so for performance, but with the caveat they only be used as temporaries
Taken from the documentation of Boost.Proto (which can be used to create expression templates):
Note An astute reader will notice that the object y defined above will be left holding a dangling reference to a temporary int. In the sorts of high-performance applications Proto addresses, it is typical to build and evaluate an expression tree before any temporary objects go out of scope, so this dangling reference situation often doesn't arise, but it is certainly something to be aware of. Proto provides utilities for deep-copying expression trees so they can be passed around as value types without concern for dangling references.
In your initial example this means that you should do:
std::cout << C(std::string("hello2")).s << std::endl;
That way the C temporary never outlives the std::string temporary. Alternatively you could make s a non reference member as others pointed out.
Since you mention C++11, in the future I expect expression trees to store by value, using move semantics to avoid expensive copying and wrappers like std::reference_wrapper to still give the option of storing by reference. This would play nicely with auto.
A possible C++11 version of your code:
class C
{
public:
explicit
C(std::string const& s_): s { s_ } {}
explicit
C(std::string&& s_): s { std::move(s_) } {}
std::string const&
get() const& // notice lvalue *this
{ return s; }
std::string
get() && // notice rvalue *this
{ return std::move(s); }
private:
std::string s; // not const to enable moving
};
This would mean that code like C("hello").get() would only allocate memory once, but still play nice with
std::string clvalue("hello");
auto c = C(clvalue);
std::cout << c.get() << '\n'; // no problem here
but is there a way to avoid this issue without using #define?
Yes.
Define your class as: (don't store the reference)
class C
{
public:
C(const std::string & p_s) : s(p_s) {}
const std::string s; //store the copy!
};
Store the copy!
Demo : http://www.ideone.com/GpSa2
The problem with your code is that std::string("hello2") creates a temporary, and it remains alive as long as you're in the constructor of C, and after that the temporary is destroyed but your object x2.s stills points to it (the dead object).
After your edit:
Storing by reference is dangerous and error prone sometimes. You should do it only when you are 100% sure that the variable reference will never go out of scope until its death.
C++ string is very optimized. Until you change a string value, all will refer to the same string only. To test it, you can overload operator new (size_t) and put a debug statement. For multiple copies of same string, you will see that the memory allocation will happen only once.
You class definition should not be storing by reference, but by value as,
class C {
const std::string s; // s is NOT a reference now
};
If this question is meant for general sense (not specific to string) then the best way is to use dynamic allocation.
class C {
MyClass *p;
C() : p (new MyClass()) {} // just an example, can be allocated from outside also
~C() { delete p; }
};
Without looking at BLAS, expression templates typically make heavy use of temporary objects of types you aren't supposed to even know exists. If Boost is storing references like this within theirs, then they would suffer the same problem you see here. But as long as those temporary objects remain temporary, and the user doesnt store them for later, everything is fine because the temporaries they reference remain alive for as long as the temporary objects do. The trick is you perform a deep copy when the intermediate object is turned into the final object that the user stores. You've skipped this last step here.
In short, it's a dangerous move, which is perfectly safe as long as the user of your library doesn't do anything foolish. I wouldn't recommend making use of it unless you have a clear need, and you're well aware of the consequences. And even then, there might be a better alternative, I've never worked with expression templates in any serious capacity.
As an aside, since you tagged this C++0x, auto x = a + b; seems like it would be one of those "foolish" things users of your code can do to make your optimization dangerous.