template <typename T>
void QVector<T>::append(const T &t)
{
const T copy(t);
const bool isTooSmall = uint(d->size + 1) > d->alloc;
if (!isDetached() || isTooSmall) {
QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
reallocData(d->size, isTooSmall ? d->size + 1 : d->alloc, opt);
}
if (QTypeInfo<T>::isComplex)
new (d->end()) T(copy);
else
*d->end() = copy;
++d->size;
}
What is the reason to make const T copy(t) instead of passing t by value into the method? What is the difference between this and:
template <typename T>
void QVector<T>::append(const T t)
{
const bool isTooSmall = uint(d->size + 1) > d->alloc;
if (!isDetached() || isTooSmall) {
QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
reallocData(d->size, isTooSmall ? d->size + 1 : d->alloc, opt);
}
if (QTypeInfo<T>::isComplex)
new (d->end()) T(t);
else
*d->end() = t;
++d->size;
}
QVector requires elements to be assignable data types, which means they
must provide a default constructor, a copy constructor, and an assignment
operator.
Their version of append enforce all, while your version will not enforce copy construction if QTypeInfo<T>::isComplex is false and optimized away.
Note: QTypeInfo<T>::isComplex is resolved at compile time.
I suspect it is a legacy requirement, as QVector already existed in Qt2, which date from 1999 well before c++ standardization.
I can think of 2 possible reasons.
It follows the style of the rest of the stl, copy and swap and pass by const &. Neither of those do any good performance or const correctness wise in this situation; but it does keep the style consistent.
Because the parameter is bound to a reference, it avoids copy elision on the function call. And because the items in a vector must be assignable( ie not const ), it avoids copy elision on the assignment into the Vector
This makes the code MUCH more portable and consistent across compilers. Which is probably a big deal for the stl.
Copy Elision Wikipedia Entry
31) When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.123 This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):
— when a temporary class object that has not been bound to a reference
(12.2) would be copied/moved to a class object with the same
cv-unqualified type, the copy/move operation can be omitted by
constructing the temporary object directly into the target of the
omitted copy/move
Related
Today I've discovered that I don't understand the C++ constructor precedence rules.
Please, see the following template struct wrapper
template <typename T>
struct wrapper
{
T value;
wrapper (T const & v0) : value{v0}
{ std::cout << "value copy constructor" << std::endl; }
wrapper (T && v0) : value{std::move(v0)}
{ std::cout << "value move constructor" << std::endl; }
template <typename ... As>
wrapper (As && ... as) : value(std::forward<As>(as)...)
{ std::cout << "emplace constructor" << std::endl; }
wrapper (wrapper const & w0) : value{w0.value}
{ std::cout << "copy constructor" << std::endl; }
wrapper (wrapper && w0) : value{std::move(w0.value)}
{ std::cout << "move constructor" << std::endl; }
};
It's a simple template value wrapper with copy constructor (wrapper const &), a move constructor (wrapper && w0), a sort of value copy constructor (T const & v0), a sort of move constructor (T && v0) and a sort of template construct-in-place-the-value constructor (As && ... as, following the example of emplace methods for STL containers).
My intention was to use the copy or moving constructor calling with a wrapper, the value copy or move constructor passing a T object and the template emplace constructor calling with a list of values able to construct an object of type T.
But I don't obtain what I expected.
From the following code
std::string s0 {"a"};
wrapper<std::string> w0{s0}; // emplace constructor (?)
wrapper<std::string> w1{std::move(s0)}; // value move constructor
wrapper<std::string> w2{1u, 'b'}; // emplace constructor
//wrapper<std::string> w3{w0}; // compilation error (?)
wrapper<std::string> w4{std::move(w0)}; // move constructor
The w1, w2 and w4 values are constructed with value move constructor, emplace constructor and move constructor (respectively) as expected.
But w0 is constructed with emplace constructor (I was expecting value copy constructor) and w3 isn't constructed at all (compilation error) because the emplace constructor is preferred but ins't a std::string constructor that accept a wrapper<std::string> value.
First question: what am I doing wrong?
I suppose that the w0 problem it's because s0 isn't a const value, so the T const & isn't an exact match.
Indeed, if I write
std::string const s1 {"a"};
wrapper<std::string> w0{s1};
I get the value copy constructor called
Second question: what I have to do to obtain what I want?
So what I have to do to make the value copy constructor (T const &) to get the precedence over the emplace constructor (As && ...) also with not constant T values and, mostly, what I have to do to get the copy constructor (wrapper const &) take the precedence constructing w3?
There is no such thing as "constructor precedence rules," there's nothing special about constructors in terms of precedence.
The two problem cases have the same underlying rule explaining them:
wrapper<std::string> w0{s0}; // emplace constructor (?)
wrapper<std::string> w3{w0}; // compilation error (?)
For w0, we have two candidates: the value copy constructor (which takes a std::string const&) and the emplace constructor (which takes a std::string&). The latter is a better match because its reference is less cv-qualified than the value copy constructor's reference (specifically [over.ics.rank]/3). A shorter version of this is:
template <typename T> void foo(T&&); // #1
void foo(int const&); // #2
int i;
foo(i); // calls #1
Similarly, for w3, we have two candidates: the emplace constructor (which takes a wrapper&) and the copy constructor (which takes a wrapper const&). Again, because of the same rule, the emplace constructor is preferred. This leads to a compile error because value isn't actually constructible from a wrapper<std::string>.
This is why you have to be careful with forwarding references and constrain your function templates! This is Item 26 ("Avoid overloading on universal references") and Item 27 ("Familiarize yourself with alternatives to overloading on universal references") in Effective Modern C++. Bare minimum would be:
template <typename... As,
std::enable_if_t<std::is_constructible<T, As...>::value, int> = 0>
wrapper(As&&...);
This allows w3 because now there is only one candidate. The fact that w0 emplaces instead of copies shouldn't matter, the end result is the same. Really, the value copy constructor doesn't really accomplish anything anyway - you should just remove it.
I would recommend this set of constructors:
wrapper() = default;
wrapper(wrapper const&) = default;
wrapper(wrapper&&) = default;
// if you really want emplace, this way
template <typename A=T, typename... Args,
std::enable_if_t<
std::is_constructible<T, A, As...>::value &&
!std::is_same<std::decay_t<A>, wrapper>::value
, int> = 0>
wrapper(A&& a0, Args&&... args)
: value(std::forward<A>(a0), std::forward<Args>(args)...)
{ }
// otherwise, just take the sink
wrapper(T v)
: value(std::move(v))
{ }
That gets the job done with minimal fuss and confusion. Note that the emplace and sink constructors are mutually exclusive, use exactly one of them.
As OP suggested, putting my comment as an answer with some elaboration.
Due to the way overload resolution is performed and types are matched, a variadic forward-reference type of constructor will often be selected as a best match. This would happen because all const qualification will be resolved correctly and form a perfect match - for example, when binding a const reference to a non-const lvalue and such - like in your example.
One way to deal with them would be to disable (through various sfinae methods at our disposal) variadic constructor when argument list matches (albeit imperfectly) to any of other available constructors, but this is very tedious, and requires ongoing support whenever extra constructors are added.
I personally prefer a tag-based approach and use a tag type as a first argument to variadic constructor. While any tag structure would work, I tend to (lazily) steal a type from C++17 - std::in_place. The code now becomes:
template<class... ARGS>
Constructor(std::in_place_t, ARGS&&... args)
And than called as
Constructor ctr(std::in_place, /* arguments */);
Since in my experience in the calling place the nature of constructor is always known - i.e. you will always know if you intend to call forward-reference accepting constructor or not - this solution works well for me.
As said in the comment, the problem is that the variadic template constructor
takes argument by forwarding reference, so it is a better match for non const lvalue copy or const rvalue copy.
There are many way to disable it, one efficient way is to always use a tag as in_place_t as proposed by SergeyA in its answer. The other is to disable the template constructor when it matches the signature of a copy constructor as it is proposed in the famous Effective C++ books.
In this case, I prefer to declare all possible signature for copy/move constructors (and also copy/move assignment). This way, whatever new constructor I add to the class, I will not have to think about avoiding copy construction, it is short 2 line of code, easy to read and it does not pollute the interface of other constructors:
template <typename T>
struct wrapper
{
//...
wrapper (wrapper& w0) : wrapper(as_const(w0)){}
wrapper (const wrapper && w0) : wrapper(w0){}
};
NB: this solution should not be used if one plan to use it as a volatile type, or if all the following condition are fullfilled:
the object size is smaller than 16bytes (or 8 byte for MSVC ABI),
all member suboject are trivially copyable,
this wrapper is going to be passed to functions where special care is taken for the case where the argument is of a trivially copyable type and its size is lower than the previous threshold because in this case, the argument can be passed in a register (or two) by passing the argument by value!
If all these requirement are fulfilled, then you may think about implementing less maintainable (error prone -> next time one will modify the code) or client interface polluting solution!
I would like to use the optional idiom inside my constexpr function to easily clarify if the variable is set or not.
What I have tried with std::experimental::optional:
constexpr bool call()
{
std::experimental::optional<bool> r;
r = true; // Error
// Similar error with:
// r = std::experimental::optional<bool>(true);
if (!r)
{
return false;
}
return *r;
}
I get the error: call to non-constexpr function - so the assignment is not possible, because this operation cannot be constexpr (Example).
But if I implement my own (very ugly, just for example) optional class, it works, because I don´t implement the assignment operator/constructor explicit.
template<typename T>
struct optional
{
bool m_Set;
T m_Data;
constexpr optional() :
m_Set(false), m_Data{}
{
}
constexpr optional(T p_Data) :
m_Set(true), m_Data(p_Data)
{
}
explicit constexpr operator bool()
{
return m_Set;
}
constexpr T operator *()
{
return m_Data;
}
};
How could I use std::..::optional in the same context with assignment inside constexpr functions?
Basically, you can't. The problem with your simple implementation is that it requires T be default-constructible - if this is not the case, this won't work.
To get around this, most implementation use either a union or some (suitably aligned) storage that can hold a T. If you are passed a T in the constructor, then all well and good, you can initialize this directly (hence it will be constexpr). However, the tradeoff here is that when calling operator=, copying the value across may require a placement-new call, which cannot be constexpr.
For example, from LLVM:
template <class _Up,
class = typename enable_if
<
is_same<typename remove_reference<_Up>::type, value_type>::value &&
is_constructible<value_type, _Up>::value &&
is_assignable<value_type&, _Up>::value
>::type
>
_LIBCPP_INLINE_VISIBILITY
optional&
operator=(_Up&& __v)
{
if (this->__engaged_)
this->__val_ = _VSTD::forward<_Up>(__v);
else
{
// Problem line is below - not engaged -> need to call
// placement new with the value passed in.
::new(_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Up>(__v));
this->__engaged_ = true;
}
return *this;
}
As for why placement new is not constexpr, see here.
This is not possible, as explained in n3527:
Making optional a literal type
We propose that optional<T> be a literal type for trivially
destructible T's.
constexpr optional<int> oi{5};
static_assert(oi, ""); // ok
static_assert(oi != nullopt, ""); // ok
static_assert(oi == oi, ""); // ok
int array[*oi]; // ok: array of size 5
Making optional<T> a literal-type in general is impossible: the
destructor cannot be trivial because it has to execute an operation
that can be conceptually described as:
~optional() {
if (is_engaged()) destroy_contained_value();
}
It is still possible to make the destructor trivial for T's which
provide a trivial destructor themselves, and we know an efficient
implementation of such optional<T> with compile-time interface —
except for copy constructor and move constructor — is possible.
Therefore we propose that for trivially destructible T's all
optional<T>'s constructors, except for move and copy constructors,
as well as observer functions are constexpr. The sketch of reference
implementation is provided in this proposal.
In other words, it's not possible to assign a value to r even if you mark it as constexpr. You must initialize it in the same line.
How could I use std::..::optional in the same context with assignment
inside constexpr functions?
std::optional is meant to hold a value that may or may not be present. The problem with std::optional's assignment is that it must destroy the old state (call the destructor of the contained object) if any. And you cannot have a constexpr destructor.
Of cause, Trivial and integral types shouldn't have a problem, but I presume the generalization was to keep things sane. However, Assignment could have been made constexpr for trivial types. Hopefully, it will be corrected. Before then, you can role out yours. :-)
Even std::optional's constructor that you think is constexpr, is actually selectively constexpr (depending on whether the selected object constructor is). Its proposal can be found here
Unfortunately, constexpr support in std::optional is somewhat rudimentary; the constexpr-enabled member functions are just the (empty and engaged) constructors, the destructor and some observers, so you cannot alter the engaged state of an optional.
This is because there would be no way to implement assignment for non-trivially copyable types without using placement new and in-place destruction of the contained object, which is illegal within constexpr context. The same currently holds for copy and move constructors, although that may change with guaranteed copy elision, but in any case the standard marks those special member functions as non-constexpr, so you cannot use them in constexpr context.
The fix would be to make the assignment operator conditionally constexpr dependent on whether the contained type is trivial (std::is_trivial_v<T>).
There is some discussion of this issue at the reference implementation; although it's probably too late to get constexpr assignment for trivial optionals into the next version of the Standard, there's nothing preventing you writing your own (e.g. by copying and fixing the reference implementation).
For class types it is possible to assign to temporary objects which is actually not allowed for built-in types. Further, the assignment operator generated by default even yields an lvalue:
int() = int(); // illegal: "expression is not assignable"
struct B {};
B& b = B() = B(); // compiles OK: yields an lvalue! ... but is wrong! (see below)
For the last statement the result of the assignment operator is actually used to initialize a non-const reference which will become stale immediately after the statement: the reference isn't bound to the temporary object directly (it can't as temporary objects can only be bound to a const or rvalue references) but to the result of the assignment whose life-time isn't extended.
Another problem is that the lvalue returned from the assignment operator doesn't look as if it can be moved although it actually refers to a temporary. If anything is using the result of the assignment to get hold of the value it will be copied rather than moved although it would be entirely viable to move. At this point it is worth noting that the problem is described in terms of the assignment operator because this operator is typically available for value types and returns an lvalue reference. The same problem exists for any function returning a reference to the objects, i.e., *this.
A potential fix is to overload the assignment operator (or other functions returning a reference to the object) to consider the kind of object, e.g.:
class G {
public:
// other members
G& operator=(G) & { /*...*/ return *this; }
G operator=(G) && { /*...*/ return std::move(*this); }
};
The possibility to overload the assignment operators as above has come with C++11 and would prevent the subtle object invalidation noted above and simultaneously allow moving the result of an assignment to a temporary. The implementation of the these two operators is probably identical. Although the implementation is likely to be rather simple (essentially just a swap() of the two objects) it still means extra work raising the question:
Should functions returning a reference to the object (e.g., the assignment operator) observe the rvalueness of the object being assigned to?
An alternatively (mentioned by Simple in a comment) is to not overload the assignment operator but to qualify it explicitly with a & to restrict its use to lvalues:
class GG {
public:
// other members
GG& operator=(GG) & { /*...*/ return *this; }
};
GG g;
g = GG(); // OK
GG() = GG(); // ERROR
IMHO, the original suggestion by Dietmar Kühl (providing overloads for & and && ref-qualifiers) is superior than Simple's one (providing it only for &).
The original idea is:
class G {
public:
// other members
G& operator=(G) & { /*...*/ return *this; }
G operator=(G) && { /*...*/ return std::move(*this); }
};
and Simple has suggested to remove the second overload. Both solutions invalidate this line
G& g = G() = G();
(as wanted) but if the second overload is removed, then these lines also fail to compile:
const G& g1 = G() = G();
G&& g2 = G() = G();
and I see no reason why they shouldn't (there's no lifetime issue as explained in Yakk's post).
I can see only one situation where Simple's suggestion is preferable: when G doesn't have an accessible copy/move constructor. Since most types for which the copy/move assignment operator is accessible also have an accessible copy/move constructor, this situation is quite rare.
Both overloads take the argument by value and there are good reasons for that if G has an accessible copy/move constructor. Suppose for now that G does not have one. In this case the operators should take the argument by const G&.
Unfortunately the second overload (which, as it is, returns by value) should not return a reference (of any type) to *this because the expression to which *this binds to is an rvalue and thus, it's likely to be a temporary whose lifetime is about to expiry. (Recall that forbidding this from happening was one of the OP's motivation.)
In this case, you should remove the second overload (as per Simple's suggestion) otherwise the class doesn't compile (unless the second overload is a template that's never instantiated). Alternatively, we can keep the second overload and define it as deleted. (But why bother since the existence of the overload for & alone is already enough?)
A peripheral point.
What should be the definition of operator = for &&? (We assume again that G has an accessible copy/move constructor.)
As Dietmar Kühl has pointed out and Yakk has explored, the code of the both overloads should be very similar and, in this case, it's better to implement the one for && in terms of the one for &. Since the performance of a move is expected to be no worse than a copy (and since RVO doesn't apply when returning *this) we should return std::move(*this). In summary, a possible one-line definition is:
G operator =(G o) && { return std::move(*this = std::move(o)); }
This is good enough if only G can be assigned to another G or if G has (non-explicit) converting constructors. Otherwise, you should instead consider giving G a (template) forwarding copy/move assignment operator taking an universal reference:
template <typename T>
G operator =(T&& o) && { return std::move(*this = std::forward<T>(o)); }
Although this is not a lot of boiler plate code it's still an annoyance if we have to do that for many classes. To decrease the amount of boiler plate code we can define a macro:
#define ASSIGNMENT_FOR_RVALUE(type) \
template <typename T> \
type operator =(T&& b) && { return std::move(*this = std::forward<T>(b)); }
Then inside G's definition one adds ASSIGNMENT_FOR_RVALUE(G).
(Notice that the relevant type appears only as the return type. In C++14 it can be automatically deduced by the compiler and thus, G and type in the last two code snippets can be replaced by auto. It follows that the macro can become an object-like macro instead of a function-like macro.)
Another way of reducing the amount of boiler plate code is defining a CRTP base class that implements operator = for &&:
template <typename Derived>
struct assignment_for_rvalue {
template <typename T>
Derived operator =(T&& o) && {
return std::move(static_cast<Derived&>(*this) = std::forward<T>(o));
}
};
The boiler plate becomes the inheritance and the using declaration as shown below:
class G : public assignment_for_rvalue<G> {
public:
// other members, possibly including assignment operator overloads for `&`
// but taking arguments of different types and/or value category.
G& operator=(G) & { /*...*/ return *this; }
using assignment_for_rvalue::operator =;
};
Recall that, for some types and contrarily to using ASSIGNMENT_FOR_RVALUE, inheriting from assignment_for_rvalue might have some unwanted consequences on the class layout.
The first problem is that this is not actually ok in C++03:
B& b = B() = B();
in that b is bound to an expired temporary once the line is finished.
The only "safe" way to use this is in a function call:
void foo(B&);
foo( B()=B() );
or something similar, where the line-lifetime of the temporaries is sufficient for the lifetime of what we bind it to.
We can replace the probably inefficient B()=B() syntax with:
template<typename T>
typename std::decay<T>::type& to_lvalue( T&& t ) { return t; }
and now the call looks clearer:
foo( to_lvalue(B()) );
which does it via pure casting. Lifetime is still not extended (I cannot think of a way to manage that), but we don't construct to objects then pointlessly assign one to the other.
So now we sit down and examine these two options:
G operator=(G o) && { return std::move(o); }
G&& operator=(G o) && { *this = std::move(o); return std::move(*this); }
G operator=(G o) && { *this = std::move(o); return std::move(*this); }
which are, as an aside, complete implementations, assuming G& operator=(G o)& exists and is written properly. (Why duplicate code when you don't need to?)
The first and third allows for lifetime extension of the return value, the second uses the lifetime of *this. The second and third modify *this, while the first one does not.
I would claim that the first one is the right answer. Because *this is bound to an rvalue, the caller has stated that it will not be reused, and its state does not matter: changing it is pointless.
The lifetime of first and third means that whomever uses it can extend the lifetime of the returned value, and not be tied to whatever *this's lifetime is.
About the only use the B operator=(B)&& has is that it allows you to treat rvalue and lvalue code relatively uniformly. As a downside, it lets you treat it relatively uniformly in situations where the result may be surprising.
std::forward<T>(t) = std::forward<U>(u);
should probably fail to compile instead of doing something surprising like "not modifying t" when T&& is an rvalue reference. And modifying t when T&& is an rvalue reference is equally wrong.
This question already has answers here:
When is the move constructor called in the `std::move()` function?
(2 answers)
Closed 9 years ago.
Just reading Stroustrup's C++ Programming Language 4th Ed and in chapter 7 he says:
move(x) means static_cast<X&&>(x) where X is the type of x
and
Since move(x) does not move x (it simply produces an rvalue reference
to x) it would have been better if move() had been called rval()
My question is, if move() just turns the variable in to an rval, what is the actual mechanism which achieves the "moving" of the reference to the variable (by updating the pointer)??
I thought move() is just like a move constructor except the client can use move() to force the compiler??
what is the actual mechanism which achieves the "moving" of the reference to the variable (by updating the pointer)??
Passing it to a function (or constructor) that takes an rvalue reference, and moves the value from that reference. Without the cast, variables cannot bind to rvalue references, and so can't be passed to such a function - this prevents variables from being accidentally moved from.
I thought move() is just like a move constructor except the client can use move() to force the compiler??
No; it's used to convert an lvalue into an rvalue in order to pass it to a move constructor (or other moving function) which requires an rvalue reference.
typedef std::unique_ptr<int> noncopyable; // Example of a noncopyable type
noncopyable x;
noncopyable y(x); // Error: no copy constructor, and can't implicitly move from x
noncopyable z(std::move(x)); // OK: convert to rvalue, then use move constructor
When you are calling move, you are just telling "Hey, I want to move this object". And when constructor accepts rvalue-reference, it understands it as "Hmm, someone want I move data from this object into myself. So, OK, I'll do it".
std::move does not moves or changes object, it just "marks" it as "ready-for-moving". And only function, that accepts rvalue reference should implement moving actual object.
This is an example, that describes the text above:
#include <iostream>
#include <utility>
class Foo
{
public:
Foo(std::size_t n): _array(new int[n])
{
}
Foo(Foo&& foo): _array(foo._array)
{
// Hmm, someone tells, that this object is no longer needed
// I will move it into myself
foo._array = nullptr;
}
~Foo()
{
delete[] _array;
}
private:
int* _array;
};
int main()
{
Foo f1(5);
// Hey, constructor, I want you move this object, please
Foo f2(std::move(f1));
return 0;
}
As in Going Native 2013, Scott Meyers gave the talk about C++ 11 features, including move.
What std::move essentially do is "unconditionally casts to a rvalue".
My question is, if move() just turns the variable in to an rval, what is the actual mechanism which achieves the "moving" of the reference to the variable (by updating the pointer)??
move does the type casting, thus the compiler will know which ctor to use. The actual move operation is done by the move ctor. You can take it as a function overloading. (ctor overloads with the rvalue parameter type.)
rvalues are generally temporary values which are discarded and destroyed immediately after creation (with a few exceptions). std::string&& is a reference to a std::string that will only bind to an rvalue. Prior to C++11, temporaries would only bind to std::string const& -- after C++11, they also bind to std::string&&.
A variable of type std::string&& behaves much like a bog-standard reference. It is pretty much only in the binding of function signatures and initialization that std::string&& differs from std::string& variables. The other way it differs is when you decltype the reference. All other uses are unchanged.
On the other hand, if a function returns a std::string&&, it is very different than returning a std::string&, because the second kind of thing that can be bound to a std::string&& is the return value of a function returning std::string&&.
std::move is the most common way to generate such a function. In a sense, it lies to the context it is in and tells it "I am a temporary, do with me what you will". So std::move takes a reference to something, and does a cast that makes it pretend to be a temporary -- aka, rvalue.
Move constructors and move assignment and other move-aware functions take an rvalue reference to know when the data they are passed is "scratch" data that they can "damage" to some extent when using it. This is very useful because many types (from containers, to std::function, to anything that uses the pImpl pattern, to non-copyable resources) can have their internal state moved much easier than it can be copied. Such a move changes the state of the source object: but because the function is told it is scratch data, that isn't impolite.
So the move happens not in std::move, but in the function that understands that the return value of std::move implies that it is permitted to modify the data in a somewhat destructive manner if that would help it.
The other ways you can get an rvalue, or an indication that the source object is "scratch data", is when you have a true temporary (an anonymous object created as the return of some other function, or one created using function-style constructor syntax), or when you return from a function with a statement of the form return local_variable;. In both cases, the data binds to rvalue references.
The short version is that std::move does not move, and std::forward does not forward, it just indicates that such an action would be allowed at this point, and lets the function/constructor being called decide what to do with that information.
from http://en.cppreference.com/w/cpp/utility/move
std::move obtains an rvalue reference to its argument and converts it
to an xvalue.
Code that receives such an xvalue has the opportunity to
optimize away unnecessary overhead by moving data out of the argument,
leaving it in a valid but unspecified state.
Return value
static_cast<typename std::remove_reference<T>::type&&>(t)
you can see move is just static_cast
by calling std::move on an object doesn't really doing anything useful, however it tells that the return value can be modified to "a valid but unspecified state"
I thought move() is just like a move constructor except the client can
use move() to force the compiler??
By essentially casting the type to an r-value type, this allows the compiler to invoke the move constructor over the copy constructor.
std::move is equivalent to static_cast<std::string&&>(x).
In the standard, it is defined like this:
template <class T>
constexpr remove_reference_t<T>&& move(T&&) noexcept;
Complementing other answers, an example could help you to better understand how rvalue references work. Take a look to the following code that emulates rvalue references:
#include <iostream>
#include <memory>
template <class T>
struct rvalue_ref
{
rvalue_ref(T& obj) : obj_ptr{std::addressof(obj)} {}
T* operator->() //For simplicity, we'll use the reference as a pointer.
{ return obj_ptr; }
T* obj_ptr;
};
template <class T>
rvalue_ref<T> move(T& obj)
{
return rvalue_ref<T>(obj);
}
template <class T>
struct myvector
{
myvector(unsigned sz) : data{new T[sz]} {}
myvector(rvalue_ref<myvector> other) //Move constructor
{
this->data = other->data;
other->data = nullptr;
}
~myvector()
{
delete[] data;
}
T* data;
};
int main()
{
myvector<int> vec(5); //vector of five integers
std::cout << vec.data << '\n'; //Print address of data
myvector<int> vec2 = move(vec); //Move data from vec to vec2
std::cout << vec.data << '\n'; //Prints zero
//Prints address of moved data (same as first output line)
std::cout << vec2.data << '\n';
}
As we can see, "move" only generates the correct alias, to indicate to the compiler which constructor overload want to use. The difference between this implementation and real rvalue references is of course that casting to rvalue reference has zero overhead, since it's only a compiler directive.
. or even allowed by the C++11 standard?
And if so, is there any compiler that actually does it?
Here is an example of what I mean:
template<class T> //T is a builtin type
class data
{
public:
constexpr
data() noexcept :
x_{0,0,0,0}
{}
constexpr
data(const T& a, const T& b, const T& c, const T& d) noexcept :
x_{a,b,c,d}
{}
data(const data&) noexcept = default;
data& operator = (const data&) noexcept = default;
constexpr const T&
operator[] (std::size_t i) const noexcept {
return x_[i];
}
T&
operator[] (std::size_t i) noexcept {
return x_[i];
}
private:
T x_[4];
};
template<class Ostream, class T>
Ostream& operator << (Ostream& os, const data<T>& d)
{
return (os << d[0] <<' '<< d[1] <<' '<< d[2] <<' '<< d[3]);
}
template<class T>
inline constexpr
data<T>
get_data(const T& x, const T& y)
{
return data<T>{x + y, x * y, x*x, y*y};
}
int main()
{
double x, y;
std::cin >> x >> y;
auto d = data<double>{x, y, 2*x, 2*y};
std::cout << d << std::endl;
//THE QUESTION IS ABOUT THIS LINE
d = get_data(x,y);
d[0] += d[2];
d[1] += d[3];
d[2] *= d[3];
std::cout << d << std::endl;
return 0;
}
Regarding the marked line:
Could the values x+y, x*y, x*x, y*y be written directly to the memory of d?
Or could the return type of get_data be directly constructed in the memory of d?
I can't think of a reason to not allow such an optimization. At least not for a class that has only constexpr constructors and default copy and assignment operators.
g++ 4.7.2 elides all copy constructors in this example; it seems however that assignment is always performed (even for default assignment only - as far as I can tell from the assembly that g++ emits).
The motivation for my question is the following situation in which such an optimization would greatly simplify and improve library design.
Suppose you write performance-critical library routines using a literal class. Objects of that class will hold enough data (say 20 doubles) that copies have to be kept to a minimum.
class Literal{ constexpr Literal(...): {...} {} ...};
//nice: allows RVO and is guaranteed to not have any side effects
constexpr Literal get_random_literal(RandomEngine&) {return Literal{....}; }
//not favorable in my opinion: possible non-obvious side-effects, code duplication
//would be superfluous if said optimization were performed
void set_literal_random(RandomEngine&, Literal&) {...}
It would make for a much cleaner (functional programming style) design if I could do without the second function. But sometimes I just need to modify a long-lived Literal object and have to make sure that I don't create a new one and copy-assign it to the one I want to modify. The modification itself is cheap, the copies aren't - that's what my experiments indicate.
EDIT:
Let's suppose the optimization shall only be allowed for a class with noexcept constexpr constructors and noexcept default operator=.
Elision of default copy/move assignment operators is allowed based on the general as-if rule only. That is the compiler can do it if it can ascertain that it will have no observable effect on behaviour.
In practice the as-if rule is used in general fashion to allow optimizations at intermediate representation and assembly levels. If the compiler can inline the default constructor and assignment, it can optimize them. It won't ever use the code of the copy constructor for it, but for their default implementations it should end up with the same code.
Edit: I answered before there was the code sample. Copy/move constructors are elided based on explicit permission to the compiler to do so, therefore they are elided even if they have observable effect (printing "COPY"). Assignments can only be elided based on as-if rule, but they have observable effect (printing "ASSIGN"), so the compiler is not allowed to touch them.
Does the standard allow for the elision of the assignment operator? Not in the same way as for construction. If you have any construct d = ..., the assignment operator will be called. If ... results in an expression of the same type as d, then the appropriate copy or move assignment operator will be called.
It is theoretically possible that a trivial copy/move assignment operator could be elided. But implementations are not allowed to elide anything that you could detect being elided.
Note that this is different from actual copy/move elision, because there the standard explicitly allows the elision of any constructor, whether trivial or not. You can return a std::vector by value into a new variable, and the copy will be elided if the compiler supports it. Even though it is very easy to detect the elision. The standard gives special permission to compilers to do this.
No such permission is granted for copy/move assignment. So it could only ever "elide" something that you couldn't tell the difference about. And that's not really "elision"; that's just a compiler optimization.
Objects of that class will hold enough data (say 20 doubles) that copies have to be kept to a minimum.
There's nothing stopping you from returning that Literal type right now. You will get elision if you store the object in a new variable. And if you copy assign it to an existing variable, you won't. But that's no different from a function which returns a float that you store into an existing variable: you get a copy of the float.
So it's really up to you how much copying you want to do.
There is an important drawback to what you propose: what would happen if the constructor threw? The behaviour for that case is well defined in the standard (all data members that had already been constructed are destructed in reverse order), but how would that translate into the case where we are "constructing" the object into an already existing one?
Your example is easy because the constructor cannot throw when T = double, but this is not so in the general case. You might end up with a half destructed object and undefined behaviour would ensue, even if your constructor and assignment operator were well behaved.
Jan Hudec's answer has a very good point about the as-if rule (+1 for him).
Hence, the assignment elision is allowed -- as he said -- provided that there's no observable effect. The fact that your assignment operator outputs "ASSIGN" is enough to prevent the optimization.
Notice that the situation is different for copy/move constructors because the standard allows elision for copy/move constructor even if they have observable side effects (see 12.8/31).