C++0x unique_ptr misunderstanding? - c++

In N2812 is an example in the Introduction where a unique_ptr is given as a value parameter
void push_back2(
std::list<std::unique_ptr<int>>& l, std::unique_ptr<int> a)
{
l.push_back(a); // oops: moves from the lvalue 'a', silently!
l.push_back(a); // oops: 'a' no longer has its original value
}
The paper discusses a problem with RValue/LValue overload resolution, but thats not my point.
I wonder, if providing the argument std::unique_ptr<int> a by-value is not causing a compiler error? It would copy it, right? And that is not allowed for unique_ptr
I am aware that the paper is quite old, maybe the definition of unique_ptr has changed, since. But maybe it's just a typo and the author wanted to write std::unique_ptr<int> &a instead?
My gcc 4.7.0 agrees with me, but thats no proof :-)
void push_back2( std::list<std::unique_ptr<int>>&, std::unique_ptr<int> ) { };
int main() {
list<unique_ptr<int>> lst;
unique_ptr<int> num { new int{4} };
push_back2(lst, num); //ERR: use of deleted function
}

There's nothing wrong with taking the parameter by value. You are correct that if you try to initialize the parameter by using a copy, you will get a compiler error since that function is deleted. However, you could initialize the value parameter by providing an rvalue as the argument. For example:
std::unique_ptr<int> myPtr{ /* ... */ }
std::list<std::unique_ptr<int>> elems;
push_back2(elems, myPtr); // Error, as you've noted
push_back2(elems, std::move(myPtr)); // Fine, uses move constructor to initialize
This syntax is nice in that it forces you to explicitly indicate that you're handing the pointer over to the function.
Once you're inside push_back2, you are correct that push_back won't be able to take in the unique_ptr because it will try to use the nonexistent copy constructor. To fix this, you'll need to use std::move again:
void push_back2(
std::list<std::unique_ptr<int>>& l, std::unique_ptr<int> a)
{
l.push_back(std::move(a)); // Fine, moves a
l.push_back(std::move(a)); // Well that was dumb, but you asked for it!
}
I hope that I interpreted your question correctly and that this is what you're looking for... let me know if there's anything else I can try to clarify!

Your knowledge and assumptions about the behavior are correct.
The paper's example is confusing as it is conflating two languages: C++ with concepts and C++ without concepts. In the paper's pretend language, the list push_back which requires CopyConstructible is SFINAE'd away, leaving only the overload requiring MoveConstructible. In such a list design, and with the old rules that an lvalue could bind to an rvalue-reference, then the push_back would have implicitly moved from a twice.
Note that we were in no danger at any time of list actually behaving this way. The authors were simply trying to set up a situation where const value_type& and value_type&& were not overloaded, and you had only value_type&& in the overload set.

You can provide it by rvalue- for example, by function return.
unique_ptr<int> make_unique() {
return unique_ptr<int>(new int);
}
int main() {
list<unique_ptr<int>> lst;
lst.push_back(make_unique());
}
In addition, you can explicitly std::move into the list.

Related

when to use move in function calls [duplicate]

This question already has answers here:
What is std::move(), and when should it be used?
(9 answers)
Closed 3 years ago.
I am currently learning more about all the c++11/14 features and wondering when to use std::move in function calls.
I know I should not use it when returning local variables, because this breaks return value optimisation, but I do not really understand where in function calls casting to a rvalue actually helps.
When a function accepts an rvalue reference, you have to provide an rvalue (either by having already a prvalue, or using std::move to create an xvalue). E.g.
void foo(std::string&& s);
std::string s;
foo(s); // Compile-time error
foo(std::move(s)); // OK
foo(std::string{}) // OK
When a function accepts a value, you can use std::move to move-construct the function argument instead of copy-constructing. E.g.
void bar(std::string s);
std::string s;
bar(s); // Copies into `s`
bar(std::move(s)); // Moves into `s`
When a function accepts a forwarding reference, you can use std::move to allows the function to move the object further down the call stack. E.g.
template <typename T>
void pipe(T&& x)
{
sink(std::forward<T>(x));
}
std::string s;
pipe(s); // `std::forward` will do nothing
pipe(std::move(s)); // `std::forward` will move
pipe(std::string{}); // `std::forward` will move
When you have some substantial object, and you're passing it as an argument to a function (e.g. an API, or a container emplace operation), and you will no longer need it at the callsite, so you want to transfer ownership, rather than copying then "immediately" losing the original. That's when you move it.
void StoreThing(std::vector<int> v);
int main()
{
std::vector<int> v{1,2,3,4,5,6/*,.....*/};
StoreThing(v);
}
// Copies `v` then lets it go out of scope. Pointless!
versus:
void StoreThing(std::vector<int> v);
int main()
{
std::vector<int> v{1,2,3,4,5,6/*,.....*/};
StoreThing(std::move(v));
}
// Better! We didn't need `v` in `main` any more...
This happens automatically when returning local variables, if RVO hasn't been applied (and note that such an "optimisation" is mandated since C++17 so you're right to say that adding a "redundant" std::move in that case can actually be harmful).
Also it's pointless to std::move if you're passing something really small (particularly a non-class thing which cannot possibly have a move constructor, let alone a meaningful one!) or you know you're passing into a function that accepts its arguments const-ly; in that case it's up to you as to whether you want to save the added source code distraction of a std::move that won't do anything: on the surface it's wise, but in a template you may not be so sure.

How to change const std::shared_ptr after first assignment?

If I define a shared_ptr and a const shared_ptr of the same type, like this:
std::shared_ptr<int> first = std::shared_ptr<int>(new int);
const std::shared_ptr<int> second = std::shared_ptr<int>();
And later try to change the value of the const shared_ptr like this:
second = first;
It cause a compile error (as it should). But even if I try to cast away the const part:
(std::shared_ptr<int>)second = first;
The result of the code above is that second ends up being Empty, while first is untouched (eg ref count is still 1).
How can I change the value of a const shared_ptr after it was originally set? Is this even possible with std's pointer?
Thanks!
It is undefined behavior to modify in any way a variable declared as const outside of its construction or destruction.
const std::shared_ptr<int> second
this is a variable declared as const.
There is no standard compliant way to change what it refers to after construction and before destruction.
That being said, manually calling the destructor and constructing a new shared_ptr in the same spot might be legal, I am uncertain. You definitely cannot refer to said shared_ptr by its original name, and possibly leaving the scope where the original shared_ptr existed is illegal (as the destructor tries to destroy the original object, which the compiler can prove is an empty shared pointer (or a non-empty one) based on how the const object was constructed).
This is a bad idea even if you could make an argument the standard permits it.
const objects cannot be changed.
...
Your cast to a shared_ptr<int> simply creates a temporary copy. It is then assigned to, and the temporary copy is changed. Then the temporary copy is discarded. The const shared_ptr<int> not being modified is expected behavior. The legality of assigning to a temporary copy is because shared_ptr and most of the std library was designed before we had the ability to overload operator= based on the r/lvalue-ness of the left hand side.
...
Now, why is this the case? Actual constness is used by the compiler as an optimization hint.
{
const std::shared_ptr<int> bob = std::make_shared<int>();
}
in the above case, the compiler can know for certain that bob is non-empty at the end of the scope. Nothing can be done to bob that could make it empty and still leave you with defined behavior.
So the compiler can eliminate the branch at the end of the scope when destroying bob that checks if the pointer is null.
Similar optimizations could occur if you pass bob to an inline function that checks for bob's null state; the compiler can omit the check.
Suppose you pass bob to
void secret_code( std::shared_ptr<int> const& );
where the compiler cannot see into the implementation of secret_code. It can assume that secret code will not edit bob.
If it wasn't declared const, secret_code could legally do a const_cast<std::shared_ptr&> on the parameter and set it to null; but if the argument to secret_code is actually const this is undefined behavior. (Any code casting away const is responsible for guaranteeing that no actual modification of an actual const value occurs by doing so)
Without const on bob, the compiler could not guarantee:
{
const std::shared_ptr<int> bob = std::make_shared<int>();
secret_code(bob);
if (bob) {
std::cout << "guaranteed to run"
}
}
that the guaranteed to run string would be printed.
With const on bob, the compiler is free to elimiate the if check above.
...
Now, do not confuse my explanation asto why the standard states you cannot edit const stack variables with "if this doesn't happen there is no problem". The standard states you shall not do it; the consequences if you do it are unbounded and can grow with new versions of your compiler.
...
From comments:
For deserialize process, which is actually a type of constructor that deserialize object from file. C++ is nice, but it got its imperfections and sometimes its OK to search for less orthodox methods.
If it is a constructor, make it a constructor.
In C++17 a function returning a T has basically equal standing to a real constructor in many ways (due to guaranteed elision). In C++14, this isn't quite true (you also need a move constructor, and the compiler needs to elide it).
So a deserialization constructor for a type T in C++ needs to return a T, it cannot take a T by-reference and be a real constructor.
Composing this is a bit of a pain, but it can be done. Using the same code for serialization and deserialization is even more of a pain (I cannot off hand figure out how).

Returning a vector by value into a reference

I have the following code:
std::vector<Info*> filter(int direction)
{
std::vector<Info*> new_buffer;
for(std::vector<Info*>::iterator it=m_Buffer.begin();it<m_Buffer.end();it++)
{
if(((*it)->direction == direction)
{
new_buffer.push_back(*it);
}
}
return new_buffer;
}
std::vector<Info*> &filteredInfo= filter(m_Direction);
Can someone explain what is happening here ? Would the filter method return by value create a temporary and filteredInfo never gets destroyed because its a reference ?
Not sure if I understand correctly. What is the diference between filteredInfo being a reference and not being one in this case ?
Your compiler should complain of that code.
This statement:
std::vector<Info*> &filteredInfo= filter(m_Direction);
is a bad idea where filter is:
std::vector<Info*> filter(int direction);
You are trying to create a reference to a temporary object. Even if it succeeds with your compiler, its illegal.
You should use:
std::vector<Info*> filteredInfo= filter(m_Direction);
Its as efficient as you want. Either a move operation (C++11) will happen there or Return Value Optimization will kick in. For your implementation of filter, it should be RVO on optimized builds (it depends on your compiler quality though) .
However, you should note that you are copying raw pointers into your vector, I hope you have a correct ownership model? If not, I advice you to use a smart pointer.
Here is what happens:
std::vector<Info*> new_buffer; creates an object locally.
return new_buffer; moves new_buffer to a temporary object when filter(m_Direction) is called.
Now if you call std::vector<Info*> filteredInfo= filter(m_Direction); the temprary object will be moved to filteredInfo so there is no unnecessary copies and it's the most efficient way.
But, if you call std::vector<Info*> &filteredInfo= filter(m_Direction); then filteredInfo is bound to a temporary object, which is a terrible idea and most compilers will complain about this.
Here you're correctly puzzled because there are two independent weird facts mixing in:
Your compiler allows a non-const reference to be bound to a temporary. This historically was a mistake in Microsoft compilers and is not permitted by the standard. That code should not compile.
The standard however, strangely enough, actually allows binding const references to temporaries and has a special rule for that: the temporary object will not be destroyed immediately (like it would happen normally) but its life will be extended to the life of the reference.
In code:
std::vector<int> foo() {
std::vector<int> x{1,2,3};
return x;
}
int main() {
const std::vector<int>& x = foo(); // legal
for (auto& item : x) {
std::cout << x << std::endl;
}
}
The reason for this apparently absurd rule about binding const references to temporaries is that in C++ there is a very common "pattern"(1) of passing const references instead of values for parameters, even when identity is irrelevant. If you combine this (anti)-pattern with implicit conversion what happens is that for example:
void foo(const std::string& x) { ... }
wouldn't be callable with
foo("Hey, you");
without the special rule, because the const char * (literal) is implicitly converted to a temporary std::string and passed as parameter bound to a const reference.
(1) The pattern is indeed quite bad from a philosophical point of view because a value is a value and a reference is a reference: the two are logically distinct concepts. A const reference is not a value and confusing the two can be the source of very subtle bugs. C++ however is performance-obsessed and, especially before move semantics, passing const references was considered a "smart" way of passing values, despite being a problem because of lifetime and aliasing issues and for making things harder for the optimizer. With a modern compiler passing a reference should be used only for "big" objects, especially ones that are not constructed on the fly to be passed or when you're actually interested in object identity and not in just object value.

In which cases should "std::move" be used in "return" statements and in which shouldn't? [duplicate]

This question already has answers here:
c++11 Return value optimization or move? [duplicate]
(4 answers)
Closed 5 years ago.
In this case
struct Foo {};
Foo meh() {
return std::move(Foo());
}
I'm pretty sure that the move is unnecessary, because the newly created Foo will be an xvalue.
But what in cases like these?
struct Foo {};
Foo meh() {
Foo foo;
//do something, but knowing that foo can safely be disposed of
//but does the compiler necessarily know it?
//we may have references/pointers to foo. how could the compiler know?
return std::move(foo); //so here the move is needed, right?
}
There the move is needed, I suppose?
In the case of return std::move(foo); the move is superfluous because of 12.8/32:
When the criteria for elision of a copy operation are met or would be
met save for the fact that the source object is a function parameter,
and the object to be copied is designated by an lvalue, overload
resolution to select the constructor for the copy is first performed as
if the object were designated by an rvalue.
return foo; is a case of NRVO, so copy elision is permitted. foo is an lvalue. So the constructor selected for the "copy" from foo to the return value of meh is required to be the move constructor if one exists.
Adding move does have a potential effect, though: it prevents the move being elided, because return std::move(foo); is not eligible for NRVO.
As far as I know, 12.8/32 lays out the only conditions under which a copy from an lvalue can be replaced by a move. The compiler is not permitted in general to detect that an lvalue is unused after the copy (using DFA, say), and make the change on its own initiative. I'm assuming here that there's an observable difference between the two -- if the observable behavior is the same then the "as-if" rule applies.
So, to answer the question in the title, use std::move on a return value when you want it to be moved and it would not get moved anyway. That is:
you want it to be moved, and
it is an lvalue, and
it is not eligible for copy elision, and
it is not the name of a by-value function parameter.
Considering that this is quite fiddly and moves are usually cheap, you might like to say that in non-template code you can simplify this a bit. Use std::move when:
you want it to be moved, and
it is an lvalue, and
you can't be bothered worrying about it.
By following the simplified rules you sacrifice some move elision. For types like std::vector that are cheap to move you'll probably never notice (and if you do notice you can optimize). For types like std::array that are expensive to move, or for templates where you have no idea whether moves are cheap or not, you're more likely to be bothered worrying about it.
The move is unnecessary in both cases. In the second case, std::move is superfluous because you are returning a local variable by value, and the compiler will understand that since you're not going to use that local variable anymore, it can be moved from rather than being copied.
On a return value, if the return expression refers directly to the name of a local lvalue (i.e. at this point an xvalue) there is no need for the std::move. On the other hand, if the return expression is not the identifier, it will not be moved automatically, so for example, you would need the explicit std::move in this case:
T foo(bool which) {
T a = ..., b = ...;
return std::move(which? a : b);
// alternatively: return which? std::move(a), std::move(b);
}
When returning a named local variable or a temporary expression directly, you should avoid the explicit std::move. The compiler must (and will in the future) move automatically in those cases, and adding std::move might affect other optimizations.
There are lots of answers about when it shouldn't be moved, but the question is "when should it be moved?"
Here is a contrived example of when it should be used:
std::vector<int> append(std::vector<int>&& v, int x) {
v.push_back(x);
return std::move(v);
}
ie, when you have a function that takes an rvalue reference, modifies it, and then returns a copy of it. (In c++20 behavior here changes) Now, in practice, this design is almost always better:
std::vector<int> append(std::vector<int> v, int x) {
v.push_back(x);
return v;
}
which also allows you to take non-rvalue parameters.
Basically, if you have an rvalue reference within a function that you want to return by moving, you have to call std::move. If you have a local variable (be it a parameter or not), returning it implicitly moves (and this implicit move can be elided away, while an explicit move cannot). If you have a function or operation that takes local variables, and returns a reference to said local variable, you have to std::move to get move to occur (as an example, the trinary ?: operator).
A C++ compiler is free to use std::move(foo):
if it is known that foo is at the end of its lifetime, and
the implicit use of std::move won't have any effect on the semantics of the C++ code other than the semantic effects allowed by the C++ specification.
It depends on the optimization capabilities of the C++ compiler whether it is able to compute which transformations from f(foo); foo.~Foo(); to f(std::move(foo)); foo.~Foo(); are profitable in terms of performance or in terms of memory consumption, while adhering to the C++ specification rules.
Conceptually speaking, year-2017 C++ compilers, such as GCC 6.3.0, are able to optimize this code:
Foo meh() {
Foo foo(args);
foo.method(xyz);
bar();
return foo;
}
into this code:
void meh(Foo *retval) {
new (retval) Foo(arg);
retval->method(xyz);
bar();
}
which avoids calling the copy-constructor and the destructor of Foo.
Year-2017 C++ compilers, such as GCC 6.3.0, are unable to optimize these codes:
Foo meh_value() {
Foo foo(args);
Foo retval(foo);
return retval;
}
Foo meh_pointer() {
Foo *foo = get_foo();
Foo retval(*foo);
delete foo;
return retval;
}
into these codes:
Foo meh_value() {
Foo foo(args);
Foo retval(std::move(foo));
return retval;
}
Foo meh_pointer() {
Foo *foo = get_foo();
Foo retval(std::move(*foo));
delete foo;
return retval;
}
which means that a year-2017 programmer needs to specify such optimizations explicitly.
std::move is totally unnecessary when returning from a function, and really gets into the realm of you -- the programmer -- trying to babysit things that you should leave to the compiler.
What happens when you std::move something out of a function that isn't a variable local to that function? You can say that you'll never write code like that, but what happens if you write code that's just fine, and then refactor it and absent-mindedly don't change the std::move. You'll have fun tracking that bug down.
The compiler, on the other hand, is mostly incapable of making these kinds of mistakes.
Also: Important to note that returning a local variable from a function does not necessarily create an rvalue or use move semantics.
See here.

Move semantics with LValue reference

So Move semantics is great, giving us higher performence.
I read this was a completly new feature and without C++11 it is 'impossible' to do this.
But could we do this before C++11? Like something that goes like the below.
class AAA
{
private:
int* m_data;
public:
AAA(int _data) : m_data(new int(_data)) { }
AAA(AAA& _other) // Not using RValue reference.
{
m_data = _other.m_data;
_other.m_data = nullptr;
}
~AAA() { delete m_data; }
};
int main()
{
AAA sth1(100);
AAA sth2(sth1)
return 0;
}
I thought that what the existence of RValue reference is for is not to make the same functions whose argument is just slighty different(like Const and Non-Const).
Simply, with RValue reference which is just another 'type', we can do both Copy constructor and Move constructor at the same time. And that's it.
Wondering if I am correct or am missing something huge.
Thanks in advance.
std::auto_ptr did exactly what you suggest. The problem was that it made behavior confusing and copying impossible. Rvalue references allow one to make classes that can be both moved and copied.
rvalue references allow automatic moving/copying based upon context (for example the moving of a temporary) trying to simulate this with an lvalue style copy constructor (which actually performed a move) would likely be disastrous.
My understanding is that move semantic is not only possible but also available as library (Boost.Move) for C++03 compilers (maybe with some restrictions). However, the language implementation might have been necessary both to allow free optimization without touching anycode and to simplify it's use as much as possible.
Yes, there is something missing, which you do not get with lvalues, even if they are non const. Non const lvalues cannot be produced from temporaries, so your attempt does not work in that case.
What if you want to pass an rvalue to your constructor? Your ctor will fail because it's non-const. With rvalue references, you can pass an rvalue to the ctor, and move from it, as rvalues are always temporaries.