If I have a constructor with n parameters such that any argument to that can be an rvalue and lvalue. Is it possible to do support this with move semantics for the rvalues without writing 2^n constructors for each possible rvalue/lvalue combination?
You take each one by value, like this:
struct foo
{
foo(std::string s, bar b, qux q) :
mS(std::move(s)),
mB(std::move(b)),
mQ(std::move(q))
{}
std::string mS;
bar mB;
qux mQ;
};
The initialization of the function parameters by the argument will either be a copy-constructor or move-constructor. From there, you just move the function parameter values into your member variables.
Remember: copy- and move-semantics are a service provided by the class, not by you. In C++0x, you no longer need to worry about how to get your own "copy" of the data; just ask for it and let the class do it:
foo f("temporary string is never copied", bar(), quz()); // no copies, only moves
foo ff(f.mS, f.mB, f.mQ); // copies needed, will copy
foo fff("another temp", f.mB, f.mQ); // move string, copy others
Note: your constructor only takes in values, those values will figure out how to construct themselves. From there, of course, it's up to you to move them where you want them.
This applies everywhere. Have a function that needs a copy? Make it in the parameter list:
void mutates_copy(std::string s)
{
s[0] = 'A'; // modify copy
}
mutates_copy("no copies, only moves!");
std::string myValue = "don't modify me";
mutates_copy(myValue); // makes copy as needed
mutates_copy(std::move(myValue)); // move it, i'm done with it
In C++03, you could emulate it fairly well, but it wasn't common (in my experience):
struct foo
{
foo(std::string s, bar b, qux q)
// have to pay for default construction
{
using std::swap; // swaps should be cheap in any sane program
swap(s, mS); // this is effectively what
swap(b, mB); // move-constructors do now,
swap(q, mQ); // so a reasonable emulation
}
std::string mS;
bar mB;
qux mQ;
};
Take the following code ideone link.
#include <iostream>
class A
{
public:
A() : i(0) {}
A(const A& a) : i(a.i) { std::cout << "Copy A" << std::endl; }
A(A&& a) : i(a.i) { std::cout << "Move A" << std::endl; }
int i;
};
template <class T>
class B1
{
public:
template <class T1, class T2>
B1(T1&& x1_, T2&& x2_) : x1(std::forward<T1>(x1_)), x2(std::forward<T2>(x2_)) {}
B1(const B1<T>& x) : x1(x.x1), x2(x.x2) { std::cout << "Copy B1" << std::endl; }
B1(B1<T>&& x) : x1(std::move(x.x1)), x2(std::move(x.x2)) { std::cout << "Move B1" << std::endl; }
private:
T x1;
T x2;
};
template <class T>
class B2
{
public:
B2(T x1_, T x2_) : x1(std::move(x1_)), x2(std::move(x2_)) {}
B2(const B2<T>& x) : x1(x.x1), x2(x.x2) { std::cout << "Copy B2" << std::endl; }
B2(B2<T>&& x) : x1(std::move(x.x1)), x2(std::move(x.x2)) { std::cout << "Move B2" << std::endl; }
private:
T x1;
T x2;
};
A&& inc_a(A&& a) { ++a.i; return static_cast<A&&>(a); }
A inc_a(const A& a) { A a1 = a; ++a1.i; return a1; }
int main()
{
A a1;
A a2;
std::cout << "1" << std::endl;
B1<A> b1(a1,a2);
std::cout << "2" << std::endl;
B1<A> b2(a1,A());
std::cout << "3" << std::endl;
B1<A> b3(A(),a2);
std::cout << "4" << std::endl;
B1<A> b4(A(),A());
std::cout << "5" << std::endl;
B2<A> b5(a1,a2);
std::cout << "6" << std::endl;
B2<A> b6(a1,A());
std::cout << "7" << std::endl;
B2<A> b7(A(),a2);
std::cout << "8" << std::endl;
B2<A> b8(A(),A());
std::cout << "9" << std::endl;
std::cout << std::endl;
std::cout << "11" << std::endl;
B1<A> b11(a1,a2);
std::cout << "12" << std::endl;
B1<A> b12(a1,inc_a(A()));
std::cout << "13" << std::endl;
B1<A> b13(inc_a(A()),a2);
std::cout << "14" << std::endl;
B1<A> b14(inc_a(A()),inc_a(A()));
std::cout << "15" << std::endl;
B2<A> b15(a1,a2);
std::cout << "16" << std::endl;
B2<A> b16(a1,inc_a(A()));
std::cout << "17" << std::endl;
B2<A> b17(inc_a(A()),a2);
std::cout << "18" << std::endl;
B2<A> b18(inc_a(A()),inc_a(A()));
std::cout << "19" << std::endl;
}
Which outputs the following:
1
Copy A
Copy A
2
Copy A
Move A
3
Move A
Copy A
4
5
Copy A
Copy A
Move A
Move A
6
Copy A
Move A
Move A
7
Copy A
Move A
Move A
8
9
11
Copy A
Copy A
12
Copy A
Move A
13
Move A
Copy A
14
Move A
Move A
15
Copy A
Copy A
Move A
Move A
16
Move A
Copy A
Move A
Move A
17
Copy A
Move A
Move A
Move A
18
Move A
Move A
Move A
Move A
19
As can be seen, the pass by value approach in B2 causes extra move for each argument in all cases except for when the argument is a prvalue.
If you want best performance, I suggest the template approach in B1. This way you have effectively have separate code for the copy and move cases, and hence only a single copy or a single move required. In the pass by value approach, at least two move/copies are required, except for the prvalue case where the compiler can construct the value in the place of the argument, in which as only one move is required.
Depending on what c++ compiler you are using, you could look into "functions with variable argument lists"
The idea is that you can pass in as many parameters as you want to the method and it just populates into an array that you can loop through.
For microsoft c++, the following blogposts might be helpful:
http://msdn.microsoft.com/en-us/library/fxhdxye9(v=VS.100).aspx
http://blogs.msdn.com/b/slippman/archive/2004/02/16/73932.aspx
Related
I am playing around with std::function and std::bind to understand how arguments are copied around and if I can save some of the copy operations.
I understand that when using std::bind, the arguments are passed by value and not reference (unless std::ref is specified). However, when I run the following snippet, the copy constructor is invoked twice. Can someone explain why?
struct token
{
static int i;
int code;
token()
: code(i++)
{
cout << __FUNCTION__ << ": " << code << endl;
}
virtual ~token()
{
cout << __FUNCTION__ << endl;
}
token (token const & other)
: code (other.code)
{
cout << "copy ctor: " << code << endl;
}
// update -- adding a move ctor
token (token const && other)
: code (std::move(other.code))
{
cout << "move ctor: " << code << endl;
}
// update -- end
void boo() const
{
cout << __FUNCTION__ << ": " << code << endl;
}
};
void call_boo(token const & t)
{
t.boo();
}
int main()
{
token t2;
cout << "default" << endl;
std::function< void () >(std::bind(&call_boo, t2));
cout << "ref" << endl;
std::function< void () >(std::bind(&call_boo, std::ref(t2)));
cout << "move" << endl;
std::function< void () >(std::bind(&call_boo, std::move(t2)));
cout << "end" << endl;
return 0;
}
When run, this produces the following output:
token: 1
default
// Without move ctor
// copy ctor: 1 // Makes sense. This is the passing by value.
// copy ctor: 1 // Why does this happen?
// With move ctor
copy ctor: 1
move ctor: 1
~token
~token
ref // No copies. Once again, makes sense.
move
// Without move ctor
// copy ctor: 1
// copy ctor: 1
// With move ctor
move ctor: 1
move ctor: 1
~token
~token
end
~token
Parameters for this constructor of std::function are always copied, so a copy of the bind object (which itself has a copy of your token object) is created inside the std::function.
http://en.cppreference.com/w/cpp/utility/functional/function/function
template< class F >
function( F f );
5) Initializes the target with a copy of f. If f is a null pointer to function or null pointer to member, *this will be empty after the call. This constructor does not participate in overload resolution unless f is Callable for argument types Args... and return type R. (since C++14)
So I have a perfect forwarder, and I want to appropriately capture it in a lambda, such that R-values are copied in, and L-values are captured by reference. However simply using std::forward doesn't do the job, as evidenced by this code:
#include<iostream>
class testClass
{
public:
testClass() = default;
testClass( const testClass & other ) { std::cout << "COPY C" << std::endl; }
testClass & operator=(const testClass & other ) { std::cout << "COPY A" << std::endl; }
};
template< class T>
void testFunc(T && t)
{ [test = std::forward<T>(t)](){}(); }
int main()
{
testClass x;
std::cout << "PLEASE NO COPY" << std::endl;
testFunc(x);
std::cout << "DONE" << std::endl;
std::cout << "COPY HERE" << std::endl;
testFunc(testClass());
std::cout << "DONE" << std::endl;
}
Compiling this with
g++ -std=c++14 main.cpp
Produces the output
PLEASE NO COPY
COPY C
DONE
COPY HERE
COPY C
DONE
In a perfect world, I would like to only have the "COPY C" appear in the rvalue case, not the lvalue case.
My work around would be to use a helper function overloaded for L- and R- values, but I was wondering if there was a better way.
Cheers!
You may use the following:
[test = std::conditional_t<
std::is_lvalue_reference<T>::value,
std::reference_wrapper<std::remove_reference_t<T>>,
T>{std::forward<T>(t)}]
Live Demo
but providing helper function seems more readable
Simple program:
#include <iostream>
using namespace::std;
class X {
public:
X() {
cout << "Default Constructor called\n";
i = 0;
}
X(int i) {
cout << "Parameterized Constructor called\n";
this->i = i;
}
X(const X& x) {
cout << "Copy Constructor called\n";
i = x.getI();
}
~X() {
cout << "Destructor called\n";
}
int getI() const {
return i;
}
X func() {
cout << "Entered func\n";
X x(2);
return x;
}
private:
int i;
};
int main() {
X x1;
X x2 = x1.func();
cout << "Returned from func\n";
}
It outputs the following:
Default Constructor called
Entered func
Parameterized Constructor called
Copy Constructor called
Destructor called
Returned from func
Destructor called
Destructor called
After the 'Returned from func' is printed, no constructor is called when creating the instance x2. I was actually expecting a copy constructor to be called when instantiating x2 as it would have been if we did something like X x2 = x1;
Now, I was told that this is a result of RVO. Is it true?
In wiki, RVO is defined as:
Return value optimization, or simply RVO, is a compiler optimization technique that involves eliminating the temporary object created to hold a function's return value.
But, I don't buy this for two reasons:
1.x2 here is not a temporary object.
2. If it were really to be the case, then the compiler would have been much better off implementing RVO when x was being returned from the function. That was a genuine case of a temporary object (during the return statement).
So, please explain why x2 was not instantiated after the function returned an object of X.
It's much easier to see what's happening if you get your functions to output more precise information. Consider:
#include <iostream>
struct X
{
X() : i_(0) { std::cout << "X(" << this << ")\n"; }
X(int i) : i_(i) { std::cout << "X(" << this << ", i " << i << ")\n"; }
X(const X& rhs) : i_(rhs.i_) { std::cout << "X(" << this << ", const X& "
<< &rhs << ")\n"; }
~X() { std::cout << "~X(" << this << ")\n"; }
X func() { std::cout << "X::func(this " << this << ")\n"; X x(2); return x; }
int i_;
};
int main()
{
X x1;
X x2 = x1.func();
std::cout << "x1 " << &x1 << ", x2 " << &x2 << '\n';
}
Output on ideone.com was:
X(0xbfd346e8)
X::func(this 0xbfd346e8)
X(0xbfd346ec, i 2)
x1 0xbfd346e8, x2 0xbfd346ec
~X(0xbfd346ec)
~X(0xbfd346e8)
That shows full RVO and elided copy-construction, which will be typical of most compilers at normal production optimisation levels (and quite possibly even lower levels).
I suggest you run the above code on your compiler with whatever flags you've been using, and the addresses displayed should make it clearer to you exactly which objects are involved in the various operations you've observed. As is, your comments...
Observe carefully. That is called after the 'func entered' is printed. That means that it got called from within the function, i.e. it was referring to the instance x, not x2.
...is flawed logic (with more attitude to boot "I'll just wait for someone who actually understands copy constructors to answer this."), which the better logging should help you realise. (Then hopefully you'll apologise to Praetorian.)
I simplified my code down to the root of the trouble:
//==============================================================================
// PRE-DEFINITIONS
#define GIVE_ME_ODD_BEHAVIOUR true
//==============================================================================
// INCLUDES
#include <iostream>
//==============================================================================
// TYPES
//------------------------------------------------------------------------------
template<typename T> struct X {
T data;
X() : data(0)
{ std::cout << "X construction # " << this << std::endl; }
template<typename TT>
X(const X<TT> & other) : data(other.data)
{ std::cout << "X construction # " << this << " from " << &other << std::endl; }
~X()
{ std::cout << "X destruction # " << this << std::endl; }
template<typename TT>
void Copy(const X<TT> & other)
{ std::cout << "X copy # " << this << " from " << &other << std::endl; }
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<typename T>
X<double> XConversion(const X<T> & other)
{
#if GIVE_ME_ODD_BEHAVIOUR
return X<double>(other);
#else
X<double> d;
d.Copy(other);
return d;
#endif
}
//==============================================================================
// MAIN
int main()
{
X<double> d;
X<int> i;
std::cout << std::endl;
d = XConversion(i);
std::cout << std::endl;
d = XConversion(d); // !!!
std::cout << std::endl;
return 0;
}
which, with
GIVE_ME_ODD_BEHAVIOUR true
gives the output:
X construction # 0x23aa70
X construction # 0x23aa60
X construction # 0x23aa80 from 0x23aa60
X destruction # 0x23aa80
X destruction # 0x23aa90 // never created !!!
X destruction # 0x23aa60
X destruction # 0x23aa70
It seems similar to THIS problem but i do have the ctor defined. I see the copy elision optimisation point here but:
why the copiler destructs the object that it optimised out and thus never created?
how can I ensure that it does not happen ?
Additional info:
I tried gcc 4.8.1 and C++ Builder XE3, optimisation off, debug compilation, both with the same result.
I tried to remove the template-ness like
struct X {
double data
...
X(const X &)
...
};
but with the same result.
One way to solve this would be, e.g., to make the cctor private and to public the Copy method only. But this would prevent me (anybody) from even returning the object from a function...
Background:
I have a set of template classes that are mutually friends and convertible. The classes share the same data but manipulate them in different ways via partial specialisation. The instances may either do soft or raw copy of the data as needed. If they do the soft copy, ref counter is increased. With the extra deletion of the instance that was actually never created, the ref counter is decreased without its prior incrementation.
Seems the compiler generates a copy constructor for your case, maybe it does not like the one with the templates (if I recall correctly copy constructors are not (or may not be) template based ... might be wrong here though)... see: Copy constructor of template class
Adding the following code:
X(const X & other) : data(other.data)
{ std::cout << "X Copy construction # " << this << " from " << &other << " as " << typeid(X).name() << std::endl; }
template<typename TT>
X(const X<TT> & other) : data(other.data)
{ std::cout << "X construction # " << this << " from " << &other << " as " << typeid(TT).name() << std::endl; }
gives the following output:
X construction # 0x7fff3496c040
X construction # 0x7fff3496c038
X construction # 0x7fff3496c020 from 0x7fff3496c038 as i
X destruction # 0x7fff3496c020
X Copy construction # 0x7fff3496c018 from 0x7fff3496c040 as 1XIdE
X destruction # 0x7fff3496c018
X destruction # 0x7fff3496c038
X destruction # 0x7fff3496c040
so there is your missing object. (tested both with clang and g++, same behaviour)
The following example, beats me. I've been so far thinking, that when functor is being used, the object gets constructed once and the same object is used multiple times, when used with for_each algorithm and that seems to be correct.
However, even though, only one object gets constructed, but multiple objects are destroyed. Now, this beats me.
class print
{
public:
void operator()(int i)
{
std::cout << i << std::endl;
}
print()
{
std::cout << "Constructor " << std::endl;
}
~print()
{
std::cout << "Destructor" << std::endl;
}
};
int main()
{
std::vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
std::cout << "After assigning values " << std::endl;
for_each(v.begin() , v.end() , print());
std::cout << "After printing values " << std::endl;
}
The output is as follows
After assigning Values
Constructor
10
20
30
Destructor
Destructor
Destructor
After printing values.
How is this possible?
Don't forget about the copy constructor (the Rule of Three can help you to remember this):
class print
{
public:
void operator()(int i)
{
std::cout << i << std::endl;
}
print()
{
std::cout << "Constructor " << std::endl;
}
print(const print& other) {
std::cout << "Copy Constructor " << std::endl;
}
~print()
{
std::cout << "Destructor" << std::endl;
}
};
int main()
{
std::vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
std::cout << "After assigning values " << std::endl;
for_each(v.begin() , v.end() , print());
std::cout << "After printing values " << std::endl;
}
Output:
After assigning values
Constructor
Copy Constructor
10
20
30
Copy Constructor
Destructor
Destructor
Destructor
After printing values
Here is how I have for_each on my system:
template<class _InIt,
class _Fn1> inline
_Fn1 _For_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{ // perform function for each element
for (; _First != _Last; ++_First)
_Func(*_First);
return (_Func); // a copy could be created here (C3)
}
template<class _InIt,
class _Fn1> inline
_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{ // perform function for each element
_DEBUG_RANGE(_First, _Last);
_DEBUG_POINTER(_Func);
return (_For_each(_Unchecked(_First), _Unchecked(_Last), _Func)); // a copy created here (C2)
}
So, essentially, this is how it could look
for_each(v.begin() , v.end() , print()); // print functor created (constructor)
// a copy created here (C1)
Now, this is completely upto the implementation if copy elision is done or not. The Standard does allow that latitude to elide away the copy constructor e.g. C3 may be eliminated.
A good way to control gcc behavior here is the -fno-elide-constructors which ensures that code does not elide away the copy constructor
You are only printing "Constructor" from the default constructor. Instances of your type can come into existance from the copy-constructor as well. Copies might be being made through the call stack. Unless you specify otherwise you get a default copy constructor for free. You can add a copy constructor and also print out "Constructor" if you want to verify this.
No matter how it's constructed, you will still see the one-and-only destructor fire and print-out "Destructor".
I would say that the for_each created copies of the print() functor which calls the implicit copy constructor defined by the compiler which doesn't appear in your code (not the same as your defined constructor above).