Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
153 views
in Technique[技术] by (71.8m points)

c++ - C++11: Move/Copy construction ambiguity?

In C++11 we can define copy and move constructors, but are both allowed on the same class? If so, how do you disambiguate their usage? For example:

Foo MoveAFoo() {
  Foo f;
  return f;
}

Is the above a copy? A move? How do I know?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Usually it will be neither due to RVO.

If that optimisation can't be performed, then it will be a move, because the object being returned is going out of scope (and will be destroyed just after). If it can't be moved, then it will be copied. If it can't be copied, it won't compile.

The whole point of move constructors is that when a copy is going to be made of an object that is just about to be destroyed, it is often unnecessary to make a whole copy, and the resources can be moved from the dying object to the object being created instead.

You can tell when either the copy or move constructor is going to be called based on what is about to happen to the object being moved/copied. Is it about to go out of scope and be destructed? If so, the move constructor will be called. If not, the copy constructor.

Naturally, this means you may have both a move constructor and copy constructor in the same class. You can also have a copy assignment operator and a move assignment operator as well.

Update: It may be unclear as to exactly when the move constructor/assignment operator is called versus the plain copy constructor/assignment operator. If I understand correctly, the move constructor is called if an object is initialised with an xvalue (eXpiring value). §3.10.1 of the standard says

An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvalue reference is an xvalue. —end example ]

And the beginning of §5 of the standard says:

[ Note: An expression is an xvalue if it is:

  • the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type,
  • a cast to an rvalue reference to object type,
  • a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or
  • a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.

In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not. —end note ]


As an example, if NRVO can be done, it's like this:

void MoveAFoo(Foo* f) {
    new (f) Foo;
}

Foo myfoo; // pretend this isn't default constructed
MoveAFoo(&myfoo);

If NRVO can't be done but Foo is moveable, then your example is a little like this:

void MoveAFoo(Foo* fparam) {
    Foo f;

    new (fparam) Foo(std::move(f));
}

Foo f; // pretend this isn't being default constructed
MoveAFoo(&f);

And if it can't be moved but it can be copied, then it's like this

void MoveAFoo(Foo* fparam) {
    Foo f;

    new (fparam) Foo((Foo&)f);
}

Foo f; // pretend this isn't default constructed
MoveAFoo(&f);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...