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
Related
Here is my situation:
I have a class that has a const reference member variable.
I attempt to initialize that member variable from a const reference.
My problem is that when the member variable is initialized in-class, a temporary copy of the object in question is made and the address of the temporary is used for the reference. When the member variable is initialized in the constructor initializer list, a copy is not made. Either way the program compiles fine without warnings in g++ 4.8.3 with either the c++11 or c++1y flags.
Below is a minimal program and output. I would just like to understand the rules of this better so I know why it occurs (or if it's a bug).
#include <iostream>
using namespace std;
struct A
{
A( )
{
cout << "creating an A at " << this << endl;
}
A( const A & a )
{
cout << "copying an A from instance at " << & a << " to instance at " << this << endl;
}
};
A g_aardvark;
const A & GetAardvark( )
{
cout << "returning an A at " << & g_aardvark << endl;
return g_aardvark;
}
struct B
{
B( )
: m_a1( GetAardvark( ) )
, m_a2( g_aardvark )
{ }
const A & m_a1;
const A & m_a2;
const A & m_a3{ GetAardvark( ) };
const A & m_a4{ g_aardvark };
};
int main( )
{
B butter;
cout << "B has m_a1 at " << & butter.m_a1 << endl;
cout << "B has m_a2 at " << & butter.m_a2 << endl;
cout << "B has m_a3 at " << & butter.m_a3 << endl;
cout << "B has m_a4 at " << & butter.m_a4 << endl;
return 0;
}
Sample output:
creating an A at 0x601494
returning an A at 0x601494
returning an A at 0x601494
copying an A from instance at 0x601494 to instance at 0x7fffc595f87f
copying an A from instance at 0x601494 to instance at 0x7fffc595f87e
B has m_a1 at 0x601494
B has m_a2 at 0x601494
B has m_a3 at 0x7fffc595f87f
B has m_a4 at 0x7fffc595f87e
This is a case of the infamous DR 1288. There was a defect in the published C++11 standard which inadvertently specified that the code:
const A & m_a4{ g_aardvark };
would actually create a temporary from g_aardvark and bind to that. This is nonsense of course, but g++ 4.8 followed the published text. The Standard was repaired by DR 1288 so that the reference binds directly.
Clang always implemented the sensible behaviour, but g++ did not update until the 4.9 chain.
See here for explanation with Standard references and a simpler testcase.
Appears to be a compiler bug as per Peregring-lk above
http://coliru.stacked-crooked.com/a/f30df5ef62b45420
I have read many posts about variadic templates and std::bind but I think I am still not understanding how they work together. I think my concepts are a little hazy when it comes to using variadic templates, what std::bind is used for and how they all tie together.
In the following code my lambda uses the dot operator with objects of type TestClass but even when I pass in objects of type std::ref they still work. How is this exactly? How does the implicit conversion happen?
#include <iostream>
using std::cout;
using std::endl;
#include <functional>
#include <utility>
using std::forward;
class TestClass {
public:
TestClass(const TestClass& other) {
this->integer = other.integer;
cout << "Copy constructed" << endl;
}
TestClass() : integer(0) {
cout << "Default constructed" << endl;
}
TestClass(TestClass&& other) {
cout << "Move constructed" << endl;
this->integer = other.integer;
}
int integer;
};
template <typename FunctionType, typename ...Args>
void my_function(FunctionType function, Args&&... args) {
cout << "in function" << endl;
auto bound_function = std::bind(function, args...);
bound_function();
}
int main() {
auto my_lambda = [](const auto& one, const auto& two) {
cout << one.integer << two.integer << endl;
};
TestClass test1;
TestClass test2;
my_function(my_lambda, std::ref(test1), std::ref(test2));
return 0;
}
More specifically, I pass in two instances of a reference_wrapper with the two TestClass objects test1 and test2, but when I pass them to the lambda the . operator works magically. I would expect that you have use the ::get() function in the reference_wrapper to make this work but the call to the .integer data member works..
The reference unwrapping is performed by the result of std::bind():
If the argument is of type std::reference_wrapper<T> (for example, std::ref or std::cref was used in the initial call to bind), then the reference T& stored in the bound argument is passed to the invocable object.
Corresponding standardese can be found in N4140 draft, [func.bind.bind]/10.
It is important to note that with std::bind;
The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or std::cref.
The "passed by reference" above is achieved because std::ref provides a result of std::reference_wrapper that is a value type that "wraps" the reference provided.
std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.
By way of an example of what bind's unwrapping of the reference does (without the bind);
#include <iostream>
#include <utility>
#include <functional>
int main()
{
using namespace std;
int a = 1;
auto b = std::ref(a);
int& c = b;
cout << a << " " << b << " " << c << " " << endl; // prints 1 1 1
c = 2;
cout << a << " " << b << " " << c << " " << endl; // prints 2 2 2
}
Demo code.
I see the C++11 documentation (http://en.cppreference.com/w/cpp/language/lambda) for lambda expressions states capture by value and reference are supported but not rvalue reference. The closest SO question I could find related to this is: How to capture a unique_ptr into a lambda expression?, but it seems like my use case doesn't require the use of std::bind.
Code
#include <iostream>
#include <memory>
class Foo
{
public:
explicit Foo(int value = 0) : mValue(value) {}
// The following items are provided just to be explicit
Foo(Foo &&other) = default;
Foo &operator=(Foo &&other) = default;
Foo(const Foo &other) = delete;
Foo &operator=(const Foo &other) = delete;
~Foo() {}
int mValue;
};
void bar(std::unique_ptr<Foo> f)
{
std::cout << "bar: " << std::dec << f->mValue << "\n";
}
int main()
{
{
std::unique_ptr<Foo> f(new Foo(22));
std::cout << "main: " << std::hex << f.get() << "\n";
// Call the bar function directly (requires using std::move)
bar(std::move(f));
std::cout << "main: " << std::hex << f.get() << "\n";
}
{
std::unique_ptr<Foo> f(new Foo(99));
std::cout << "main: " << std::hex << f.get() << "\n";
// Lamda expression captures 'f' by reference and then calls the bar function (again, requires using std::move)
auto fn = [&f](){ bar(std::move(f)); };
fn(); // Execute the closure
std::cout << "main: " << std::hex << f.get() << "\n";
}
return 0;
}
Example Output
main: 0x92e010
bar: 22
main: 0
main: 0x92e010
bar: 99
main: 0
By examining the output it appears this program is running correctly (i.e., the observed results are what I expected. However, I have the following questions.
Questions
Is using the closure equivalent to the code that calls the bar function directly?
I'm asking explicitly since the documentation (see beginning of the question) about lambda expressions didn't state anything about using std::move on captured references (i.e., I want to make sure this doesn't run afoul of undefined behavior or similar bad outcomes).
If the answer to the first question is "you can't use std::move on the captured reference", then what is the right way to do this (e.g., the std::bind solution, etc)?
Is using the closure equivalent to the code that calls the bar function directly?
Yes, they're equivalent in this code. Captured references aren't special in any way that I can think of: you have fully defined behavior, as long as f is in scope and can be moved from.
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)
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