Related
I wish to create a wrapper around std::make_pair that takes a single argument and uses that argument to make the first and second members of the pair. Furthermore, I wish to take advantage of move semantics.
Naively, we might write (ignoring return types for clarity),
template <typename T>
void foo(T&& t)
{
std::make_pair(std::forward<T>(t),
std::forward<T>(t));
}
but this is unlikely to do what we want.
What we want is:
In the case where foo is called with a (const) lvalue reference argument, we should pass that (const) reference on to std::make_pair unmodified for both arguments.
In the case where foo is called with an rvalue reference argument, we should duplicate the referenced object, then call std::make_pair with the original rvalue reference as well as an rvalue reference to the newly created object.
What I've come up with so far is:
template <typename T>
T forward_or_duplicate(T t)
{
return t;
}
template <typename T>
void foo(T&& t)
{
std::make_pair(std::forward<T>(t),
forward_or_duplicate<T>(t));
}
But I'm reasonably sure it's wrong.
So, questions:
Does this work? I suspect not in that if foo() is called with an rvalue reference then T's move constructor (if it exists) will be called when constructing the T passed by value to forward_or_duplicate(), thus destroying t.
Even if it does work, is it optimal? Again, I suspect not in that T's copy constructor will be called when returning t from forward_or_duplicate().
This seems like a common problem. Is there an idiomatic solution?
So, questions:
Does this work? I suspect not in that if foo() is called with an rvalue reference then T's move constructor (if it exists) will be
called when constructing the T passed by value to
forward_or_duplicate(), thus destroying t.
No, t in foo is an lvalue, so constructing the T passed by value to
forward_or_duplicate() from t calls the copy constructor.
Even if it does work, is it optimal? Again, I suspect not in that T's copy constructor will be called when returning t from
forward_or_duplicate().
No, t is a function parameter, so the return implicitly moves, and doesn't copy.
That said, this version will be more efficient and safer:
template <typename T>
T forward_or_duplicate(std::remove_reference_t<T>& t)
{
return t;
}
If T is an lvalue reference, this results in the same signature as before. If T is not a reference, this saves you a move. Also, it puts T into a non-deduced context, so that you can't forget to specify it.
Your exact code works. Slight variations of it (ie, not calling make_pair but some other function) result in unspecified results. Even if it appears to work, subtle changes far from this line of code (which are locally correct) can break it.
Your solution isn't optimal, because it can copy a T twice, even when it works, when it only needs to copy it once.
This is by far the easiest solution. It doesn't fix the subtle breaks caused by code elsewhere changing, but if you are really calling make_pair that is not a concern:
template <typename T>
void foo(T&& t) {
std::make_pair(std::forward<T>(t),
static_cast<T>(t));
}
static_cast<T>(t) for a deduced type T&& is a noop if T&& is an lvalue, and a copy if T&& is an rvalue.
Of course, static_cast<T&&>(t) can also be used in place of std::forward<T>(t), but people don't do that either.
I often do this:
template <typename T>
void foo(T&& t) {
T t2 = t;
std::make_pair(std::forward<T>(t),
std::forward<T>(t2));
}
but that blocks a theoretical elision opportunity (which does not occur here).
In general, calling std::forward<T>(t) on the same function call as static_cast<T>(t) or any equivalent copy-or-forward function is a bad idea. The order in which arguments are evaluated is not specified, so if the argument consuming std::forward<T>(t) is not of type T&&, and its constructor sees the rvalue T and moves state out of it, the static_cast<T>(t) could evaluate after the state of t has been ripped out.
This does not happen here:
template <typename T>
void foo(T&& t) {
T t2 = t;
std::make_pair(std::forward<T>(t),
std::forward<T>(t2));
}
because we move the copy-or-forward to a different line, where we initialize t2.
While T t2=t; looks like it always copies, if T&& is an lvalue reference, T is also an lvalue reference, and int& t2 = t; doesn't copy.
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.
1)
template<typename T, typename Arg>
shared_ptr<T> factory(Arg arg)
{
return shared_ptr<T>(new T(arg));
}
2)
template<typename T, typename Arg>
shared_ptr<T> factory(Arg& arg)
{
return shared_ptr<T>(new T(arg));
}
3)
template<typename T, typename Arg>
shared_ptr<T> factory(Arg const & arg)
{
return shared_ptr<T>(new T(arg));
}
*)Why is number 3 is preferred than number 1 and number 2?
*)if factory(41) is called, why is called on rvalue?
*)# define BOOST_ASIO_MOVE_ARG(type) type&&. what's && in this case?
Actually, approach #3 is not better than 1 and 2. It all depends on T's constructor(s).
A somewhat standard way to do this is using rvalue references, which are the && you mention.
So, a better factory would be something like this: (which is what perfect forwarding actually is)
template<typename T, typename Arg>
std::shared_ptr<T> factory(Arg && arg)
{
return std::shared_ptr<T>(new T (std::forward<Arg>(arg)));
}
Due to reference collapsing rules of C++, this function can take (and forward) both rvalue refences and lvalue references, i.e., if you pass it an rvalue, it will forward that rvalue faithfully to T's constructor, and if you give it an lvalue, the two kinds of reference (Something & && arg) will collapse and the lvalue reference will be forwarded to the underlying constructor.
I think I covered your questions here, but to answer explicitly,
#3 is not the preferred method here. Even before C++11, you probably wanted both const& and & overloads of the factory function. The const& version is nicer and it will actually accept temporary values, but if your underlying T type has a constructor that accepts a non-const ref, then you would get a compile error because a const& is not implicitly casted to a &.
Because you can't take the address of the literal 41 (this is not 100% technically correct, but I think it's OK to think of lvalues and rvalues this way.)
It signifies an rvalue reference. You need to read about that; an explanation will not fit here, and there are already several great ones just a Google search away!
UPDATE: As mentioned tangentially in the comments, using make_shared can be better than constructing a shared_ptr with a just-newed pointer. make_shared might achieve better efficiency by allocating the control block (which includes the reference count) along with the object itself, which would provide better cache locality when accessing the reference counter and the object, and also may save one memory allocation. Even if the implementation has none of the optimizations, it won't be any worse than the above version. So use std::make_shared whenever possible! And this would be how you do it here:
template<typename T, typename Arg>
std::shared_ptr<T> factory (Arg && arg)
{
return std::make_shared<T>(std::forward<Arg>(arg));
}
*)Why is number 3 is preferred than number 1 and number 2?
(1) won't work if Arg is non-copyable.
(2) won't allow you to pass an rvalue, as in factory<int>(42);
Note that none of the three examples involve perfect forwarding. I'm not sure what the subject of your question refers to.
*)if factory(41) is called, why is called on rvalue?
I'm not sure I understand the question. 41 is an rvalue by definition.
*)# define BOOST_ASIO_MOVE_ARG(type) type&&. what's && in this case?
type&& is an rvalue reference to type.
the following are 2 of weak_ptr's constructors:
http://msdn.microsoft.com/en-us/library/bb982126.aspx
weak_ptr(const weak_ptr&);
template<class Other>
weak_ptr(const weak_ptr<Other>&);
actual code (from memory):
weak_ptr(const weak_ptr& _Other)
{ // construct weak_ptr object for resource pointed to by _Other
this->_Resetw(_Other);
}
template<class _Ty2>
weak_ptr(const weak_ptr<_Ty2>& _Other,
typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
void *>::type * = 0)
{ // construct weak_ptr object for resource pointed to by _Other
this->_Resetw(_Other);
}
Q1: Why is the top copy constructor even there? It looks like the bottom one accounts for every case (including the top one). Does it even get called? and if they didn't include it would the bottom one take it's place?
Q2: What's going on with the second argument of the bottom (templated) constructor. I think I understand the SFINAE aspect, but I don't understand why there is an extra * after ::type
Q1) If you don't write a copy constructor, the compiler will generate one for you, which wouldn't be what you want. Templated conversion constructors don't count.
Q2) Remember that shared_ptr<T> is like a T*, convertibility must be checked at the level of pointers. If T* is convertible to U* then you should be able to assign one to the other. Think of pointers-to-base. [Sorry, that wasn't what you asked.] The final argument type just needs to exist, but also we don't want to have to specify the argument itself. A universal way of making up a type for which we can also provide a default argument is a pointer. In short, we need to make the function depend on a type that may or may not exist, but without actually requiring the user to know about this.
Re Q1: a templated constructor is never a "copy constructor", even if it manages to copy. if there is no user-defined "copy constructor", then the compiler will generate one as needed.
Re Q2: the second argument, a pointer defaulted to 0, is just to have a place to put the enable_if. you can find more about that (if i recall correctly) in the Boost documentation.
Cheers & hth.,
This is a follow-on question to
C++0x rvalue references and temporaries
In the previous question, I asked how this code should work:
void f(const std::string &); //less efficient
void f(std::string &&); //more efficient
void g(const char * arg)
{
f(arg);
}
It seems that the move overload should probably be called because of the implicit temporary, and this happens in GCC but not MSVC (or the EDG front-end used in MSVC's Intellisense).
What about this code?
void f(std::string &&); //NB: No const string & overload supplied
void g1(const char * arg)
{
f(arg);
}
void g2(const std::string & arg)
{
f(arg);
}
It seems that, based on the answers to my previous question that function g1 is legal (and is accepted by GCC 4.3-4.5, but not by MSVC). However, GCC and MSVC both reject g2 because of clause 13.3.3.1.4/3, which prohibits lvalues from binding to rvalue ref arguments. I understand the rationale behind this - it is explained in N2831 "Fixing a safety problem with rvalue references". I also think that GCC is probably implementing this clause as intended by the authors of that paper, because the original patch to GCC was written by one of the authors (Doug Gregor).
However, I don't this is quite intuitive. To me, (a) a const string & is conceptually closer to a string && than a const char *, and (b) the compiler could create a temporary string in g2, as if it were written like this:
void g2(const std::string & arg)
{
f(std::string(arg));
}
Indeed, sometimes the copy constructor is considered to be an implicit conversion operator. Syntactically, this is suggested by the form of a copy constructor, and the standard even mentions this specifically in clause 13.3.3.1.2/4, where the copy constructor for derived-base conversions is given a higher conversion rank than other user-defined conversions:
A conversion of an expression of class type to the same class type is given Exact Match rank, and a conversion
of an expression of class type to a base class of that type is given Conversion rank, in spite of the fact that
a copy/move constructor (i.e., a user-defined conversion function) is called for those cases.
(I assume this is used when passing a derived class to a function like void h(Base), which takes a base class by value.)
Motivation
My motivation for asking this is something like the question asked in How to reduce redundant code when adding new c++0x rvalue reference operator overloads ("How to reduce redundant code when adding new c++0x rvalue reference operator overloads").
If you have a function that accepts a number of potentially-moveable arguments, and would move them if it can (e.g. a factory function/constructor: Object create_object(string, vector<string>, string) or the like), and want to move or copy each argument as appropriate, you quickly start writing a lot of code.
If the argument types are movable, then one could just write one version that accepts the arguments by value, as above. But if the arguments are (legacy) non-movable-but-swappable classes a la C++03, and you can't change them, then writing rvalue reference overloads is more efficient.
So if lvalues did bind to rvalues via an implicit copy, then you could write just one overload like create_object(legacy_string &&, legacy_vector<legacy_string> &&, legacy_string &&) and it would more or less work like providing all the combinations of rvalue/lvalue reference overloads - actual arguments that were lvalues would get copied and then bound to the arguments, actual arguments that were rvalues would get directly bound.
Clarification/edit: I realize this is virtually identical to accepting arguments by value for movable types, like C++0x std::string and std::vector (save for the number of times the move constructor is conceptually invoked). However, it is not identical for copyable, but non-movable types, which includes all C++03 classes with explicitly-defined copy constructors. Consider this example:
class legacy_string { legacy_string(const legacy_string &); }; //defined in a header somewhere; not modifiable.
void f(legacy_string s1, legacy_string s2); //A *new* (C++0x) function that wants to move from its arguments where possible, and avoid copying
void g() //A C++0x function as well
{
legacy_string x(/*initialization*/);
legacy_string y(/*initialization*/);
f(std::move(x), std::move(y));
}
If g calls f, then x and y would be copied - I don't see how the compiler can move them. If f were instead declared as taking legacy_string && arguments, it could avoid those copies where the caller explicitly invoked std::move on the arguments. I don't see how these are equivalent.
Questions
My questions are then:
Is this a valid interpretation of the standard? It seems that it's not the conventional or intended one, at any rate.
Does it make intuitive sense?
Is there a problem with this idea that I"m not seeing? It seems like you could get copies being quietly created when that's not exactly expected, but that's the status quo in places in C++03 anyway. Also, it would make some overloads viable when they're currently not, but I don't see it being a problem in practice.
Is this a significant enough improvement that it would be worth making e.g. an experimental patch for GCC?
What about this code?
void f(std::string &&); //NB: No const string & overload supplied
void g2(const std::string & arg)
{
f(arg);
}
...However, GCC and MSVC both reject g2 because of clause 13.3.3.1.4/3, which prohibits lvalues from binding to rvalue ref arguments. I understand the rationale behind this - it is explained in N2831 "Fixing a safety problem with rvalue references". I also think that GCC is probably implementing this clause as intended by the authors of that paper, because the original patch to GCC was written by one of the authors (Doug Gregor)....
No, that's only half of the reason why both compilers reject your code. The other reason is that you can't initialize a reference to non-const with an expression referring to a const object. So, even before N2831 this didn't work. There is simply no need for a conversion because a string is a already a string. It seems you want to use string&& like string. Then, simply write your function f so that it takes a string by value. If you want the compiler to create a temporary copy of a const string lvalue just so you can invoke a function taking a string&&, there wouldn't be a difference between taking the string by value or by rref, would it?
N2831 has little to do with this scenario.
If you have a function that accepts a number of potentially-moveable arguments, and would move them if it can (e.g. a factory function/constructor: Object create_object(string, vector, string) or the like), and want to move or copy each argument as appropriate, you quickly start writing a lot of code.
Not really. Why would you want to write a lot of code? There is little reason to clutter all your code with const&/&& overloads. You can still use a single function with a mix of pass-by-value and pass-by-ref-to-const -- depending on what you want to do with the parameters. As for factories, the idea is to use perfect forwarding:
template<class T, class... Args>
unique_ptr<T> make_unique(Args&&... args)
{
T* ptr = new T(std::forward<Args>(args)...);
return unique_ptr<T>(ptr);
}
...and all is well. A special template argument deduction rule helps differentiating between lvalue and rvalue arguments and std::forward allows you to create expressions with the same "value-ness" as the actual arguments had. So, if you write something like this:
string foo();
int main() {
auto ups = make_unique<string>(foo());
}
the string that foo returned is automatically moved to the heap.
So if lvalues did bind to rvalues via an implicit copy, then you could write just one overload like create_object(legacy_string &&, legacy_vector &&, legacy_string &&) and it would more or less work like providing all the combinations of rvalue/lvalue reference overloads...
Well, and it would be pretty much equivalent to a function taking the parameters by value. No kidding.
Is this a significant enough improvement that it would be worth making e.g. an experimental patch for GCC?
There's no improvement.
I don't quite see your point in this question. If you have a class that is movable, then you just need a T version:
struct A {
T t;
A(T t):t(move(t)) { }
};
And if the class is traditional but has an efficient swap you can write the swap version or you can fallback to the const T& way
struct A {
T t;
A(T t) { swap(this->t, t); }
};
Regarding the swap version, I would rather go with the const T& way instead of that swap. The main advantage of the swap technique is exception safety and is to move the copy closer to the caller so that it can optimize away copies of temporaries. But what do you have to save if you are just constructing the object anyway? And if the constructor is small, the compiler can look into it and can optimize away copies too.
struct A {
T t;
A(T const& t):t(t) { }
};
To me, it doesn't seem right to automatically convert a string lvalue to a rvalue copy of itself just to bind to a rvalue reference. An rvalue reference says it binds to rvalue. But if you try binding to an lvalue of the same type it better fails. Introducing hidden copies to allow that doesn't sound right to me, because when people see a X&& and you pass a X lvalue, I bet most will expect that there is no copy, and that binding is directly, if it works at all. Better fail out straight away so the user can fix his/her code.