Is an Object Guaranteed to Be Moved When It Is Returned

Is an object guaranteed to be moved when it is returned?

Yes. See [class.copy] p32

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. If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to
the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. — end note ]

Is the sub-object of a temporary object guaranteed to be moved on return?

The cleanest formulation of the "implicit move" rule is in [class.copy.elision]/3 of the current working paper:

In the following copy-initialization contexts, a move operation might
be used instead of a copy operation:

  • If the expression in a return statement ([stmt.return]) is a (possibly parenthesized) id-expression that names an object with
    automatic storage duration declared in the body or
    parameter-declaration-clause of the innermost enclosing function or lambda-expression, or

  • [...]


overload resolution to select the constructor for the copy is first
performed as if the object were designated by an rvalue. If the first
overload resolution fails or was not performed, or if the type of the
first parameter of the selected constructor is not an rvalue reference
to the object's type (possibly cv-qualified), overload resolution is
performed again, considering the object as an lvalue.

Neither b.a nor coll[0] is an id-expression. Therefore, there is no implicit move. If you want a move, you'll have to do it explicitly.

How do I know if object passed as r-value will get moved?

Well, if the function accept a universal reference and you want to forbid moving, there are many options for you to choose from, among others:

  1. Pass by constant reference (C++17 has std::as_const() to simplify that).
  2. Save it as a local and don't convert to rvalue-reference. Seems you do that.
  3. Use something to explicitly convert an rvalue-reference to an lvalue-reference.

Of course, unless the lambda captures locals by value which have different move-semantics than copy-semantics, and the called function actually takes advantage of that, the point is moot.

Will it actually take the opportunity?

Examine the contract, and then simply trust in it or try to verify the implementation. There is no shortcut.

Let's not even mention that C++ allows the programmer to explicitly opt out of the (limited) safety it provides.

When is the destructor of an object that is being moved to called in C++?

In the first version the object gets destroyed for the first time as part of returning the object constructed in getSomeA. Its return statement effectively constructs a temporary object, which then gets assigned to main's b1. If you ignore the process of returning from a function, the sequence of events is:

A <temporary object>(std::bind( ... )

b1=<temporary object>

<temporary object gets destroyed>

At this point the bound function gets called, as a result of the temporary object gets destroyed. The temporary object is a fully tricked out object, with all the rights and privileged granted thereof. Including a destructor.

But wait, there's more! b1 is a perfect bit-by-bit copy of the original object, with the bound function, before it got destroyed. So when b1 gets destroyed, the function gets called again.

This is the indirect consequence of the Rule Of Three. When an object owns a resource, and must maintain an exclusive ownership of the resource you will need to provide a copy and/or move constructor and and assignment operator to spell out exactly what should happen in that situation.

P.S. these rules change slightly with C++17's guaranteed copy elision, but the underlying concept is still the same.

Is it allowed to self-move an object in C++?

From cpp ref:

Also, the standard library functions called with xvalue arguments may assume the argument is the only reference to the object; if it was constructed from an lvalue with std::move, no aliasing checks are made. However, self-move-assignment of standard library types is guaranteed to place the object in a valid (but usually unspecified) state:

std::vector<int> v = {2, 3, 3};
v = std::move(v); // the value of v is unspecified

Why isn't object returned by std::move destroyed immediately

Moving from an object doesn't change its lifetime, only its current value. Your object foo is destroyed on return from main, which is after your output.

Futhermore, std::move doesn't move from the object. It just returns an rvalue reference whose referand is the object, making it possible to move from the object.

Is it okay to Move an object from a queue, if you're about to pop from it?

Yes, this is perfectly safe:

std::queue<T> q;
// add stuff...

T top = std::move(q.front());
q.pop();

pop() doesn't have any preconditions on the first element in the q having a specified state, and since you're not subsequently using q.front() you don't have to deal with that object being invalidated any more.

Sounds like a good idea to do!

Is it allowed to return a moved object as a const lvalue reference?

Well, yes but it won't do anything.

The std::move function is just a cast to a rvalue reference. So in effect:

std::string s;
std::move(s); // returns std::string&& to `s`

So it just returns a reference to the object you pass in.

So in your code, you create an rvalue reference to your string s, but you bind that reference to a std::string const&, which cannot be moved from.

You'd be better simply returning the reference directly:

const string &release() {
return s;
}

Or return by move (using exchange):

std::string release() {
return std::exchange(s, std::string{});
// s valid to be reused, thanks to std::exchange
}

The last solution would be to return an rvalue reference, but I wouldn't do that, as it won't guarantee the reference to be moved from.

How to return object after vector.push_back(std::move(Object))?

Is the component guaranteed to be moved and added?

No, because you're "moving" the pointer. And allocations don't get "moved" like that. In fact, there's no reason for you to std::move() if you're using a pointer anyway.

Also, Like @rustyx suggested, you probably want to use std::unique_ptr<Component> rather than Component*, as that will take care of deallocating the memory when the vector is destroyed.

Will the reference to the returned object be valid?

Yes, but it may become invalid if you add another component. Remember that back() will not give you a Component*, but rather a Component*&.

So what you probably want to return is actually *component.

Are there any additional checks necessary for this function (in your opinion)?

Other than the above - seriously consider avoiding the vector of pointers in favor of something else. dynamic polymorphism is out of fashion :-P ... have you considered variants?


Putting things together:

#include <memory>
#include <vector>
#include <type_traits>

template<typename T, typename... TArgs>
T& addComponent(TArgs&&... args)
{
static_assert(std::is_base_of<Component, T>::value,
"Trying to add a 'component' whose type does not inherit Component");
T* component = new T(std::forward<TArgs>(args)...);
Components.emplace_back(static_cast<Component*>(component));
return *component;
}

// ...

std::vector<std::unique_ptr<Component>> components;


Related Topics



Leave a reply



Submit