Question about std::move

C

crea

I am trying to learn this std::move. A simple question, but I have not found
answer after googling.

Trying to understand why this code swaps the strings:

string s = "Orig s";
string t("Orig t");
t = std::move(s);

so now s is "Orig t"

1) Is it because string-classes move-constructor swaps them? It sets s to be
t? If this is the case, are *all* move contructors doing this? Are all std
library constructors doing this? Should all move-contructor do this
(swapping)? How do I know which classes move contructors swap values?
2) I hear them saying that "after move s is in an unspecified state".
Meaning it has a value which can basically be anything. Why they say like
that if s is t (in this case)? Why the websites confuse me with this... ??
:). It clearly is *not* in an unspecified state if it has the value of t.

If somebody can clear these would be good. I can go forward... :)
thanks
 
P

peter koch

Den fredag den 22. november 2013 10.36.23 UTC+1 skrev crea:
I am trying to learn this std::move. A simple question, but I have not found

answer after googling.

Trying to understand why this code swaps the strings:

string s = "Orig s";
string t("Orig t");
t = std::move(s);

so now s is "Orig t"

You can not rely on that.
1) Is it because string-classes move-constructor swaps them? It sets s to be
t? If this is the case, are *all* move contructors doing this? Are all std
library constructors doing this? Should all move-contructor do this
(swapping)? How do I know which classes move contructors swap values?

Your current implementation swaps them, but there is no guarantee.
2) I hear them saying that "after move s is in an unspecified state".
Meaning it has a value which can basically be anything. Why they say like
that if s is t (in this case)? Why the websites confuse me with this... ??
:). It clearly is *not* in an unspecified state if it has the value of t.
After the move, s can hold anything so long as the state of s is valid - the
constructor must be able to run.
That your implementation did a swap was quite smart. This means that there was
no need to run any clean-up code in t. You delegate that to the destructor of
s which has to run anyway.

/Peter
 
C

crea

peter koch said:
Den fredag den 22. november 2013 10.36.23 UTC+1 skrev crea:

You can not rely on that.

Strange that people on the net then make these examples and talk about "swap
happened".
Your current implementation swaps them, but there is no guarantee.

But its not my implementation... its sdt::string ., you noticed that? Its
clearly std::string contructor which is doing the swap, isnt it?
After the move, s can hold anything so long as the state of s is valid -
the
constructor must be able to run.

you mean destructor?
That your implementation did a swap was quite smart.

std library did that...

This means that there was
 
C

crea

peter koch said:
Den fredag den 22. november 2013 10.36.23 UTC+1 skrev crea:

You can not rely on that.

oh ok. So then it goes more like I was thinking: Its not genarally meant to
be a swap.... just some implementations can do that and I have to know it.
 
B

Barry Schwarz

I am trying to learn this std::move. A simple question, but I have not found
answer after googling.

Trying to understand why this code swaps the strings:

string s = "Orig s";
string t("Orig t");
t = std::move(s);
so now s is "Orig t"
1) Is it because string-classes move-constructor swaps them? It sets s to be
t? If this is the case, are *all* move contructors doing this? Are all std
library constructors doing this? Should all move-contructor do this
(swapping)? How do I know which classes move contructors swap values?

Why are you making a general assumption based on one specific example?
How many different compilers have you tested this with. How many
different types of arguments?
2) I hear them saying that "after move s is in an unspecified state".
Meaning it has a value which can basically be anything. Why they say like
that if s is t (in this case)? Why the websites confuse me with this... ??
:). It clearly is *not* in an unspecified state if it has the value of t.

Why do you think it will always have the value of t? If s had a
different value, for example " ", your question would not change. You
would want to know why it got changed to a single blank. The fact
that s is now unspecified means the compiler (or library) writer can
generate code to do anything he wants with s as long as it ends up
valid. t is a valid value that is no better and no worse than
anything else.
If somebody can clear these would be good. I can go forward... :)

The contents of s are unspecified. Why do you care what value it ends
up with? The fact that your system seems to swap the values is not
something you should depend on. Move forward and don't evaluate s
until you give it a new value.
 
V

Victor Bazarov

oh ok. So then it goes more like I was thinking: Its not genarally meant to
be a swap.... just some implementations can do that and I have to know it.

No, you *don't have to* know that. You shouldn't *care* about that if
your goal is to *move* the value to 't'. There are two things that are
known about the operation, (a) that the value of 't' is going to be what
used to be in 's', and (b) that the value of 's' *may* no longer be what
it was.

The 'move' is an operation with *relaxed* requirements compared to
'copy' or 'swap'. Use it when you *don't care* what the value of 's' is
after the operation.

If you need to swap the values, there is 'std::swap' for that, and its
effects you need to know in order to use it.

Get yourself a copy of "The C++ Standard Library" by Nicolai Josuttis.
Don't try to invent rationale by observing the behavior of a single
implementation (or even of a couple of them), get it from "the horse's
mouth". And get a copy of the Standard while you're at it.

V
 
A

Alf P. Steinbach

I am trying to learn this std::move.

Well IMHO its name is a bit misleading. It sounds like std::move moves,
or that it guarantees a move. But on the contrary, all it does is to
tell (to an assignment or initialization destination) that in your
opinion the argument /can/ be moved, i.e. that the particular value of
that argument after this does not matter to you.

So I think std::move should have been std::movable, or -- but it gets
too verbose -- std::discardable or std::pilferable. :)

Anyway, it indicates the movability (that you don't care what happens
with the argument) by producing an rvalue reference (T&&), importantly
with the invocation expression as an rvalue.

C++11 §5.2.2/10
"A function call is an lvalue if the result type is an lvalue reference
type or an rvalue reference to function type, an xvalue if the result
type is an rvalue reference to object type, and a prvalue otherwise."

From §3.10 (you need fixed width font to see this properly):

expression
/ \
glvalue rvalue
/ \ / \
lvalue xvalue prvalue

To see what kind of value an expression is, go upward in the chain. So
`move( x )` is an xvalue, by 5.2.2/10, which up to the right says it is
also an rvalue. Just as in C++03 /every/ expression is either an lvalue
or an rvalue, but the finer classification in C++11 helps with things.

And when the expression is an rvalue, as in this case, it can be bound
to an rvalue reference formal argument. I.e., your std::move rvalue
expression can be bound to the argument of a /move constructor/ or a
/move assignment operator/. In this way `std::move` directs the overload
resolution, choosing which constructor or assignment op.

A simple question, but I have not found answer after googling.

Trying to understand why this code swaps the strings:

string s = "Orig s";
string t("Orig t");
t = std::move(s);

so now s is "Orig t"

You can't rely on such behavior.

As far as the Holy Standard is concerned, what happens here is that

1 std::move( s ) produces a string&&, importantly /as an rvalue/.

2 That rvalue expression can be bound to the /move assignment/
operator's formal argument, which is string&& (if the expression was an
lvalue then it couldn't be so bound, and the normal copy assignment
operator would be chosen).

3 The move assignment operator is free to plunder and rape (whatever)
the argument, in order to yield the outward appearance of a value
assignment to everybody who agree to not look at the possibly quite
sorry state of s afterwards.

The purpose of this is to do things more efficiently when that's possible.

I.e. it's an /optimization/, designed to yield the same logical effect
as a copy assignment, when one just ignores that which does not matter.

1) Is it because string-classes move-constructor swaps them? It sets s to be
t? If this is the case, are *all* move contructors doing this? Are all std
library constructors doing this? Should all move-contructor do this
(swapping)? How do I know which classes move contructors swap values?

For your particular implementation the values are swapped. They're
swapped by the move assignment operator. It is a simple implementation
strategy for moving, a valid way to move, whose purpose is to let the
destructor of the argument object take care of cleanup.

2) I hear them saying that "after move s is in an unspecified state".
Meaning it has a value which can basically be anything. Why they say like
that if s is t (in this case)? Why the websites confuse me with this... ??

Much information on the internets is vague and unreliable.

:). It clearly is *not* in an unspecified state if it has the value of t.

It's unspecified by the C++ standard (the C++ standard does not specify)
whether your implementation will produce t or something else.

If the implementation makes that a guarantee, then you can rely on that
guarantee for your implementation, regardless of the C++ standard.

If it doesn't (and why should it), then all you have to rely on for
portability is the C++ standard.

However, many people tend to forget that there is a practical /purpose/
in the end, and talk about e.g. general "UB" (as if UB could be a
context independent property) etc. Just keep in mind what you're doing
and why. With respect to the C++ standard, the value is unspecified.

If somebody can clear these would be good. I can go forward... :)
thanks


Cheers & hth.,

- Alf
 
C

crea

Barry Schwarz said:
Why are you making a general assumption based on one specific example?
How many different compilers have you tested this with. How many
different types of arguments?

No, its just that couple of websites seemed to indicate that it can be a
pure swap. But seems like its not really....
The contents of s are unspecified. Why do you care what value it ends
up with?

because if I *know* that move is always a swap as well, then i can use it as
a swap.

The fact that your system seems to swap the values is not
something you should depend on.

ok, if its not a rule

Move forward and don't evaluate s
 
C

crea

allows its destructor to be called.
Therefore, a copy is a valid move, which is what will happen if you
move a fundamental type, as is a swap. What happens to your string is
implementation defined, and you now know what your implementation
happens to do.

then obviously there is no point in trusting that its a swap generally
speaking
 
C

crea

Juha Nieminen said:
That's because there's no guarantee that the data will actually be moved,
even if you use std::move(). The data may just as well be copied in the
normal way. This happens most usually when the class has no move
constructor/assignment operator, in which case the regular copy
constructor/assignment is called.

But in this case, do we know that std::string will always do this... swap
like this? Or i was just lucky ... it only happens in my computer?
The only thing std::move() does is to create an rvalue-reference to its
parameter, nothing more. It's then up to the code handling that to do
whatever it wants with it.

ok, but we are talking here about std library behaviour, not any class. I
know I could do whatever I want to s in my own class, but the question is
more like are std-classes doing swap always.
 
C

crea

Ok, good stuff - very good. I ll read all this carefully in time.

Alf P. Steinbach said:
Well IMHO its name is a bit misleading. It sounds like std::move moves, or
that it guarantees a move. But on the contrary, all it does is to tell (to
an assignment or initialization destination) that in your opinion the
argument /can/ be moved, i.e. that the particular value of that argument
after this does not matter to you.

You can't rely on such behavior.

Ok, so this is what I wanted to know. Hmm, i have to double check the sites
I was reading as I think they did say its doing a swap.. :)

for the rest I need more time to read.. :)
 
S

sg

Am 22.11.2013 14:30, schrieb crea:
But in this case, do we know that std::string will always do this... swap
like this? Or i was just lucky ... it only happens in my computer?

Generally, the "moved-from" state for some type could be anything. The
only safe assumption is that you can still properly destruct the object.
Many of the standard library algorithms also rely on "moved-from"
objects being assignable. So, if one writes a move-enabled class one
should take care to leave an object in a destructible and assignable
state (if the type is assignable in "normal" states, too) when the
object is being moved from.

Certain types make special guarantees. For example, if you move a
std::unique_ptr we know for sure that the source unique_ptr object will
compare equal to nullptr. We know this because unique_ptr has been
specified that way. However, std::string does not make such a guarantee.
See §21.4.2:

basic_string(const basic_string<charT,traits,Allocator>& str);
basic_string(basic_string<charT,traits,Allocator>&& str) noexcept;

Effects: Constructs an object of class basic_string as indicated
in Table 64. In the second form, str is left in a valid state
with unspecified value.

This is for the move constructor. The move assignment operator also does
not make any kind of quarantee:

basic_string<charT,traits,Allocator>&
operator=(basic_string<charT,traits,Allocator>&& str) noexcept;

Effects: if *this and str are not the same object, modifies
*this as shown in Table 71. [Note: A valid implementation is
swap(str) -- end note]

Table 71
operator=(const basic_string<charT,trait,Allocator>&&) effects

data() points at the array whose first element was
pointed at by str.data()
size() previous value of str.size()
capacity() a value at least as large as size()

There is no mention of what happens to str, the source of the move.
ok, but we are talking here about std library behaviour, not any class. I
know I could do whatever I want to s in my own class, but the question is
more like are std-classes doing swap always.

No, they don't. The file streams don't do swapping in their move
assignment, as far as I know. If they did, some file might be left open
for too long and that's not good.

But for strings it's okay to swap. This way, the moved-from strings can
keep some heap memory that could be reused when they are the target of
another assignment.

Cheers!
SG
 
T

Tobias Müller

crea said:
[...]
The only thing std::move() does is to create an rvalue-reference to its
parameter, nothing more. It's then up to the code handling that to do
whatever it wants with it.

ok, but we are talking here about std library behaviour, not any class. I
know I could do whatever I want to s in my own class, but the question is
more like are std-classes doing swap always.

Why are you still insisting on that? If you want to swap, just use
std::swap.

There is not just one implementation of the C++ standard library and the
behavior can change even between different versions of the same standard
library.
Standard libraries are even permitted to decide only at runtime. For
example if the string class uses small string optimization it may be faster
not to copy small string values from the target to the source.

[...]

Tobi
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top