views:

147

answers:

5

After moving an object, it must be destructable:

T obj;
func(std::move(obj));
// don't use obj and let it be destroyed as normal

But what else can be done with obj? Could you move another object into it?

T obj;
func(std::move(obj));
obj = std::move(other);

Does this depend on the exact type? (E.g. std::vector could make specific guarantees you can't rely on for all T.) Is it required or even sane that all types support something besides destruction on moved-from objects?

+3  A: 

Yes, you can move another object into it. std::swap does this.

Henrik
I'd forgotten std::swap, good point.
Roger Pate
The appears to be the only sane requirement, in addition to destruction, for any type. I'll note that the move-assignment operator could be deleted (thus yielding a compile-time error) and that swap requires MoveAssignable (§20.3.2p1, 0x FCD) to make this work—implying some types, which can't be used with swap, *aren't* MoveAssignable.
Roger Pate
And it appears has\_move\_assign (§20.7.4.3, table 45, 0x FCD) tells you whether MoveAssignable is met.
Roger Pate
@Roger Concepts were removed from the standard.
Let_Me_Be
@Let: The referenced sections are not part of the concepts proposal, and the FCD was published ~9 months after concepts were removed. As you put it in another comment, "you should probably read something about [these], you seem to have no idea what they are."
Roger Pate
@Roger I didn't know that they tweaked type traits this much. Sorry, should have checked the draft immediately.
Let_Me_Be
A: 

That's type semantics. You decide. It's up to you how you implement the move.

In general, the state should be the same as the one gained by using non-parametric constructor.

Btw. move makes only sense if you are storing a data block behind a pointer (or some other movable class).

Let_Me_Be
I'm asking as a user of these types, not as an implementor. "If I write a function templated on T, what operations do I know work for any T?" T can be anything from int to std::vector to, well, *anything* else.
Roger Pate
@Roger: If you write a function template, then you have requirements on the types that can be passed. If the type doesn't meet the requirements its wrongly used.
Let_Me_Be
@Let: That's why I'm asking what requirements are guaranteed for any type. For example, see the answers pointing out moved-from objects can be moved-into ("move-assigned").
Roger Pate
@Roger Well, in that case its super simple. There are absolutely no guarantees.
Let_Me_Be
@Let: There is already a guarantee pointed out: you can move-assign into it.
Roger Pate
@Roger No, its just that no-one actually understood what you are asking.
Let_Me_Be
I'm upvoting to counter the downvote. @Roger, you're asking what guarantees you have for an object whose type models MoveConstructible. The mere fact that you can apply `std::move` to your object does not imply that you can assign to it.
avakar
@avakar: See my comments on Henrik's answer.
Roger Pate
@Roger, I don't understand, is my previous point incorrect? (I'm defending the answer because I think that given the question, the answer "you decide" and "there are no guarantees" is correct. Only now I realize that you might not have been the downvoter so my comment might have been misdirected.)
avakar
@avakar: Ah, you assuming I was the downvoter makes more sense, but "it's completely up to you" isn't helpful. MoveAssignable being required if you ever want to use a type with swap or containers, for example, is. "Let" said he misunderstood me; I thought he was going to delete this answer after posting the second. I was asking for "sane" requirements and guidance, which aren't here either.
Roger Pate
+1  A: 
Alex Farber
I'm asking what the exact requirements for that consistent state are. The way I understand things currently, after func(std::move(obj));, you are not guaranteed obj.method() can be called, unless you know exactly what T is and know it guarantees that to be okay.
Roger Pate
@Roger Of course you are allowed to call `obj.method();` The object doesn't go anywhere. It just changed state.
Let_Me_Be
@Let: By "you are not guaranteed obj.method() can be called", I mean "you are not guaranteed obj.method() isn't UB.". I realize the syntax is well-formed.
Roger Pate
@Roger I have no idea what UB is but anyway, if the move operator gets the class into a state where you can't call methods from public interface it's just not implemented correctly.
Let_Me_Be
Alex Farber
@Let: [Undefined Behavior](http://stackoverflow.com/questions/2046952/limit-the-confusion-caused-by-undefined-behavior/2047172#2047172)
Roger Pate
@Alex Why make your class movable if you can't move?
Let_Me_Be
@Alex: I'm not writing moving code, I'm writing a function templated on T which moves objects. T can be anything from int to std::vector to, well, *anything* else. "If this is impossible, object methods must throw some known..." – where is this stated, or is it just your advice? (It sounds like good advice, but it's not as strong as I'm looking for.)
Roger Pate
@Roger Well, its definitely not UB. You could call it IB (but I only use that when talking about compiler, not user code).
Let_Me_Be
@Let: What guarantees it's not UB? Do you know any section in the 0x FCD or WD relating to this?
Roger Pate
@Roger Because that wouldn't make logical sense. When the standard allows you to implement something, that alone means its not UB. As I already said you could call it IB.
Let_Me_Be
@Let: I can't understand what you're saying.
Roger Pate
@Alex: The edit is wrong. Calling move on local variables is very much part of the reason it exists and not UB.
Roger Pate
@Roger You should probably read something about the rvalue references, you seem to have no idea what they are: http://www.artima.com/cppsource/rvalue.html
Let_Me_Be
@Roger Pate I didn't say that using move on local variables is UB (UB - I like it!). But incorrect class implementation may cause UB. std::move is done to apply it to rvalue references, which are formally not rvalue references, as shown in my code. Applying them to local variables is side effect.
Alex Farber
@Alex: Then I don't understand what you mean by "When std::move is used for variable which is not actually rvalue reference, really, this variable usability may be undefined."
Roger Pate
@Alex Well, if you use it on something that isn't a rvalue reference its the same as calling a function that takes a lvalue reference on something that isn't a lvalue reference.
Let_Me_Be
+4  A: 

The current draft of C++0x requires that a moved-from object can be destroyed or assigned to. If you pass your object to a function in the standard library then that is all that is assumed.

It is generally considered good practice to ensure that a moved-from object is a "working" object of its type that satisfies all invariants. However, it is in an unspecified state --- if it is a container, you don't know how many elements it has, or what they are, but you should be able to call size() and empty(), and query it.

The current draft is unclear on what is required of the standard library types themselves, and there is active discussion in the C++ committee about that.

Anthony Williams
It may be a good idea to allow users to call a size() method, but if I write my own container, am I allowed to make obj.size() be UB if obj has been moved?
Roger Pate
Yes, with your own type you can do what you like. I would strongly recommend adding a `valid()` query if you do though, as undetectable states that "explode" when used are a real pain to deal with.
Anthony Williams
I wouldn't say every move-enabled class has to support assignment. But if the class does support some sort of assignment(s) this/these should still be usable in a "moved-from" state.
sellibitze
As for containers, David Abrahams at least recommends that the move-assigned-to container should destruct its original elements somehow. Consider vector<fstream> where move assignment is implemented via swap. That's not a good idea because old stream objects might still live on in the other vector instead of being closed.
sellibitze
The C++0x library requires that a move-enabled class supports assignment to moved-from objects, so if you have a `std::vector<MyClass>` then `MyClass` had better support assignment after move. If you don't use your class with the standard library then you can do what you like.
Anthony Williams
A: 

As I finally understood from the comments. You should check this: http://www.boost.org/doc/libs/1_44_0/libs/concept_check/concept_check.htm

This will allow you to check the type supplied as template parameters for concepts (features of the type). I'm not sure if they already have one for movable.

Let_Me_Be