How Can I avoid implicit move constructor inside a lambda function - c++

I am using "emplace" method to avoid memory copy.
But, when I am using the "emplace" inside a Lambda function. It always call implicit move constructor.
How I can avoid memory copy inside a Lambda function?
This sample program should not print “I am being moved.”
#include <vector>
#include <iostream>
struct A
{
int a;
A(int t) : a(t)
{
std::cout << "I am being constructed.\n";
}
A(A&& other) : a(std::move(other.a))
{
std::cout << "I am being moved.\n";
}
};
std::vector<A> g_a;
int main()
{
std::cout << "emplace_back:\n";
g_a.emplace_back(1);
std::cout << "emplace_back in lambda:\n";
auto f1 = [](int x) { g_a.emplace_back(x); };
f1(2);
std::cout << "\nContents: ";
for (A const& t : g_a)
std::cout << t.a << " ";
std::cout << std::endl;
}

It's not about the lambda function but rather about the vector that reallocates its memory. You can ammend this with std::vector::reserve.
int main() {
g_a.reserve(10);
^^^^^^^^^^^^^^^^
std::cout << "emplace_back:\n";
g_a.emplace_back(1);
std::cout << "emplace_back in lambda:\n";
auto f1 = [](int x) { g_a.emplace_back(x); };
f1(2);
std::cout << "\nContents: ";
for (A const& t : g_a)
std::cout << t.a << " ";
std::cout << std::endl;
}
Live Demo

Related

Move (or copy) capture variadic template arguments into lambda

I am attempting to figure out how to move (or just copy if a move is not available) variadic parameters into a lambda within a templated function.
I am testing this with a move-only class (see below) because this would be the "worst-case" that needs to work with my template.
class MoveOnlyTest {
public:
MoveOnlyTest(int a, int b = 20, int c = 30) : _a(a), _b(b), _c(c) {
std::cout << "MoveOnlyTest: Constructor" << std::endl;
}
~MoveOnlyTest() {
std::cout << "MoveOnlyTest: Destructor" << std::endl;
}
MoveOnlyTest(const MoveOnlyTest& other) = delete;
MoveOnlyTest(MoveOnlyTest&& other) :
_a(std::move(other._a)),
_b(std::move(other._b)),
_c(std::move(other._c))
{
std::cout << "MoveOnlyTest: Move Constructor" << std::endl;
other._a = 0;
other._b = 0;
other._c = 0;
}
MoveOnlyTest& operator=(const MoveOnlyTest& other) = delete;
MoveOnlyTest& operator=(MoveOnlyTest&& other) {
if (this != &other) {
_a = std::move(other._a);
_b = std::move(other._b);
_c = std::move(other._c);
other._a = 0;
other._b = 0;
other._c = 0;
std::cout << "MoveOnlyTest: Move Assignment Operator" << std::endl;
}
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const MoveOnlyTest& v) {
os << "{a=" << v._a << "}";
return os;
}
private:
int _a;
int _b;
int _c;
};
And here is the test code I am attempting to get working:
void test6() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 6 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test6_A(std::move(v));
}
void test6_A(MoveOnlyTest v) {
std::cout << "test6_A()" << std::endl;
test6_B(test6_C, v);
}
template <typename ... ARGSF, typename ... ARGS>
void test6_B(void(*fn)(ARGSF...), ARGS&&... args) {
std::cout << "test6_B()" << std::endl;
//What do I need to get args to be moved/copied into the lambda
auto lambda = [fn, args = ???]() mutable {
(*fn)( std::forward<ARGS>(args)... );
};
lambda();
}
void test6_C(MoveOnlyTest v) {
std::cout << "test6_C()" << std::endl;
std::cout << "v = " << v << std::endl;
}
I am trying to have the exact same behavior as below, only using a generic template so that I can create a lambda which captures and arguments, and calls any function with those arguments.
void test5() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 5 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test5_A(std::move(v));
}
void test5_A(MoveOnlyTest v) {
std::cout << "test5_A()" << std::endl;
auto lambda = [v = std::move(v)]() mutable {
test5_B(std::move(v));
};
lambda();
}
void test5_B(MoveOnlyTest v) {
std::cout << "test5_B()" << std::endl;
std::cout << "v = " << v << std::endl;
}
To be clear, I don't want to perfectly capture the arguments as in c++ lambdas how to capture variadic parameter pack from the upper scope I want to move them if possible and, if not, copy them (the reason being is that I plan to store this lambda for later execution thus the variables in the stack will no longer be around if they are just captured by reference).
To be clear, I don't want to perfectly capture the arguments as in c++
lambdas how to capture variadic parameter pack from the upper scope I
want to move them if possible
Just using the same form:
auto lambda = [fn, ...args = std::move(args)]() mutable {
(*fn)(std::move(args)...);
};
In C++17, you could do:
auto lambda = [fn, args = std::tuple(std::move(args)...)]() mutable {
std::apply([fn](auto&&... args) { (*fn)( std::move(args)...); },
std::move(args));
};

c++: Use templates to wrap any lambda inside another lambda

I want to make a function that can wrap any lambda to log start/end calls on it.
The code below works except for:
any lambda that has captures
any lambda that returns void (although this can easily be fixed by writing a second function)
#include <iostream>
#include <functional>
template <class T, class... Inputs>
auto logLambda(T lambda) {
return [&lambda](Inputs...inputs) {
std::cout << "STARTING " << std::endl;
auto result = lambda(inputs...);
std::cout << "END " << std::endl;
return result;
};
}
int main() {
int a = 1;
int b = 2;
// works
auto simple = []() -> int {
std::cout << "Hello" << std::endl; return 1;
};
logLambda(simple)();
// works so long as explicit type is declared
auto with_args = [](int a, int b) -> int {
std::cout << "A: " << a << " B: " << b << std::endl;
return 1;
};
logLambda<int(int, int), int, int>(with_args)(a, b);
// Does not work
// error: no matching function for call to ‘logLambda<int(int), int>(main()::<lambda(int)>&)’
auto with_captures = [&a](int b) -> int {
std::cout << "A: " << a << " B: " << b << std::endl;
return 1;
};
logLambda<int(int), int>(with_captures)(b);
}
Is there any way to do this? Macros are also acceptable
Use Raii to handle both void and non-void return type,
and capture functor by value to avoid dangling reference,
and use generic lambda to avoid to have to specify argument your self
It results something like:
template <class F>
auto logLambda(F f) {
return [f](auto... args) -> decltype(f(args...)) {
struct RAII {
RAII() { std::cout << "STARTING " << std::endl; }
~RAII() { std::cout << "END " << std::endl; }
} raii;
return f(args...);
};
}
Call look like:
const char* hello = "Hello";
logLambda([=](const char* s){ std::cout << hello << " " << s << std::endl; })("world");
Demo
That code has undefined behavior.
auto logLambda(T lambda) {
return [&lambda]
You are capturing local parameter by reference.

Eliding copy/move when taking members out of a temporary

I'd like to take out members of a temporary without unnecessary moving or copying.
Suppose I have:
class TP {
T _t1, _t2;
};
I'd like to get _t1, and _t2 from TP(). Is it possible without copying/moving members?
I've tried with tuples and trying to "forward" (I don't think it's possible) the members, but the best I could get was a move, or members dying immediately.
In the following playground using B::as_tuple2 ends up with members dying too soon, unless the result is bound to a non-ref type, then members are moved. B::as_tuple simply moves is safe with auto on client side.
I suppose this should be technically possible, since the temporary dies immediately, and the member do die while they could bound to variables on the calling site (Am I wrong?), and structured binding of a similar struct works as intended.
Is it possible to extend/pass life of the member onto an outside variable, or elide the move/copy? I need it with c++14 version, but I couldn't get it to work on c++17 either, so I am interested in both.
Playground:
#include <tuple>
#include <iostream>
using std::cout;
class Shawty {
/**
* Pronounced shouty.
**/
public:
Shawty() : _id(Shawty::id++) {cout << _id << " ctor\n"; }
Shawty(Shawty && s) : _id(Shawty::id++) { cout << _id << " moved from " << s._id << "\n"; }
Shawty(const Shawty & s) : _id(Shawty::id++) { cout << _id << " copied from " << s._id << "\n"; }
Shawty& operator=(Shawty && s) { cout << _id << " =moved from " << s._id << "\n"; return *this;}
Shawty& operator=(Shawty & s) { cout << _id << " =copied from " << s._id << "\n"; return *this;}
~Shawty() {cout << _id << " dtor\n"; }
int _id;
static int id;
};
int Shawty::id = 0;
class B {
public:
auto as_tuple() && {return std::make_tuple(std::move(_s1), std::move(_s2));}
auto as_tuple2() && {return std::forward_as_tuple(std::move(_s1), std::move(_s2));}
private:
Shawty _s1, _s2;
};
struct S {
Shawty _s1, _s2;
};
int main() {
std::cout << "----------\n";
auto [s1, s2] = B().as_tuple2();
std::cout << "---------\n";
auto tpl1 = B().as_tuple2();
std::cout << "----------\n";
std::tuple<Shawty, Shawty> tpl2 = B().as_tuple2();
std::cout << "----------\n";
std::cout << std::get<0>(tpl1)._id << '\n';
std::cout << std::get<1>(tpl1)._id << '\n';
std::cout << std::get<0>(tpl2)._id << '\n';
std::cout << std::get<1>(tpl2)._id << '\n';
std::cout << s1._id << '\n';
std::cout << s2._id << '\n';
std::cout << "--struct--\n";
auto [s3, s4] = S{};
std::cout << s3._id << '\n';
std::cout << s4._id << '\n';
std::cout << "----------\n";
return 0;
}
No. It is not possible to extend the lifetime of more than one member beyond the lifetime of the super object.
So, the only way to "get" members without copying is to keep the super object alive, and refer to them:
// member function
auto as_tuple3() & {
return std::make_tuple(std::ref(_s1), std::ref(_s2));
}
// usage
B b;
auto [s1, s2] = b.as_tuple3();
An example of extending lifetime of the object by binding a reference to a single member. Note that this requires the member to be accessible from where the reference is bound (not the case in your example, where the member is private):
auto&& s1 = B{}._s1;
Add support for structured binding to your B type.
class B {
public:
template<std::size_t I, class Self,
std::enable_if_t< std::is_same_v<B, std::decay_t<Self>>, bool> = true
>
friend constexpr decltype(auto) get(Self&& self) {
if constexpr(I==0)
{
using R = decltype(std::forward<Self>(self)._s1)&&;
return (R)std::forward<Self>(self)._s1;
}
else if constexpr(I==1)
{
using R = decltype(std::forward<Self>(self)._s2)&&;
return (R)std::forward<Self>(self)._s2;
}
}
private:
Shawty _s1, _s2;
};
namespace std {
template<>
struct tuple_size<::B>:std::integral_constant<std::size_t, 2> {};
template<std::size_t N>
struct tuple_element<N, ::B>{using type=Shawty;};
}
Test code:
int main() {
std::cout << "----------\n";
{
auto&& [s1, s2] = B();
}
}
output:
----------
0 ctor
1 ctor
1 dtor
0 dtor
Live example.
This is the best I can do. Note that s1 and s2 are references into a lifetime-extended version of B.

Destructor running twice on class instance declared inside lambda capture specifier

When running the following code, it seems that the destructor is running twice. I have a theory that this might have to do with an automatic move constructor being added, but I'm not sure how to test this.
#include <iostream>
#include <functional>
struct Structure {
Structure(int n) :
Value(n) {
std::cout << "constructor: " << Value << std::endl;
}
~Structure() {
std::cout << "destructor: " << Value << std::endl;
}
int Value;
};
int main() {
int Init = 4;
std::function<void()> Function = [Instance = Structure(Init)] () {
std::cout << "Value is: " << Instance.Value << std::endl;
};
Function();
Function();
return 0;
}
Output:
constructor: 4
destructor: 4
Value is: 4
Value is: 4
destructor: 4
Is this output correct?
std::function works by copying the callable object you provide. There is no copy-elision here, since your lambda is not an std::function but of an anonymous, unrelated type.
Hence, the two destructors you see are:
The Instance member of the original, temporary, lambda;
The Instance member of the copy of the lambda that was stored into the std::function and lived until the end of main.
Ok, I defined the move and copy constructors manually and also saw errors when I instructed the compiler to delete them in a variant of the code below. Everything seems normal.
Revised code:
#include <iostream>
#include <functional>
struct Structure {
Structure(int n) :
Value(n) {
std::cout << "constructor: " << Value << std::endl;
}
Structure(const Structure& other) :
Value(other.Value) {
std::cout << "copy constructor: " << Value << std::endl;
}
Structure(Structure&& other) :
Value(other.Value) {
other.Value = -1;
std::cout << "move constructor: " << Value << std::endl;
}
~Structure() {
std::cout << "destructor: " << Value << std::endl;
}
int Value;
};
int main() {
int Init = 4;
std::function<void()> Function = [Instance = Structure(Init)] () {
std::cout << "Value is: " << Instance.Value << std::endl;
};
Function();
Function();
return 0;
}
Output:
constructor: 4
move constructor: 4
destructor: -1
Value is: 4
Value is: 4
destructor: 4

std::map::clear and elements' destructors

Does destructor get called on std::map elements when std::map::clear is used?
I tried to debug for std::map<string,string> but could not see std::string destructor getting invoked. Can any one please help my understanding?
Documentation states it gets called, but I could not notice it.
Documentation is right, it does get called.
The destruction will be done by the method std::allocator<T>::deallocate(). Trace through that in your debugger.
http://www.cplusplus.com/reference/std/memory/allocator/
The destructor does get called. Here is an example to illustrate:
#include <iostream>
#include <map>
class A
{
public:
A() { std::cout << "Constructor " << this << std::endl; }
A(const A& other) { std::cout << "Copy Constructor " << this << std::endl; }
~A() { std::cout << "Destructor " << this <<std::endl; }
};
int main()
{
std::map<std::string, A> mp;
A a;
mp.insert(std::pair<std::string, A>("hello", a));
mp.clear();
std::cout << "Ending" << std::endl;
}
This will report an output similar to this:
Constructor 0xbf8ba47a
Copy Constructor 0xbf8ba484
Copy Constructor 0xbf8ba48c
Copy Constructor 0x950f034
Destructor 0xbf8ba48c
Destructor 0xbf8ba484
Destructor 0x950f034
Ending
Destructor 0xbf8ba47a
So, you can see that the destructors get called by the calling the clear function.
try with a std::map<A,B> where A and B are custom types that have a destructor in which you have set a breakpoint. You will see that it does get invoked, and exactly what scope this destruction happens at.
Here is a bit more of a complete test, building on Chris Mansley's code as I wanted to see the effect on values, ptrs and refs - and I wanted to see the difference
between clear and erase. No difference. In summary the destructor is only called
for value types, which you would expect. I just like to check my understanding 8)
#include <iostream>
#include <map>
class A
{
public:
std::string some_data;
A(std::string some_data) : some_data(some_data) {
std::cout << " A(" << some_data << ") #" << this << std::endl;
}
A(const A& other) {
some_data = other.some_data;
std::cout << " Copy A(" << other.some_data << ") #" << this << std::endl;
}
~A() {
std::cout << " Destruct ~A(" << some_data << ") #" << this << std::endl;
}
};
void clear_test_value (void)
{
std::cout << "clear_test_value() {" << std::endl;
std::map<std::string, A> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A>("key1", a));
mp.clear();
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void erase_test_value (void)
{
std::cout << "erase_test_value() {" << std::endl;
std::map<std::string, A> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A>("key2", a));
auto f = mp.find("key2");
if (f == mp.end()) {
std::cout << "failed to find element {" << std::endl;
return;
}
mp.erase(f);
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void clear_test_ptr (void)
{
std::cout << "clear_test_ptr() {" << std::endl;
std::map<std::string, A*> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A*>("key1", &a));
mp.clear();
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void erase_test_ptr (void)
{
std::cout << "erase_test() {" << std::endl;
std::map<std::string, A*> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A*>("key2", &a));
auto f = mp.find("key2");
if (f == mp.end()) {
std::cout << "failed to find element {" << std::endl;
return;
}
mp.erase(f);
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void clear_test_ref (void)
{
std::cout << "clear_test_ref() {" << std::endl;
std::map<std::string, A&> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A&>("key1", a));
mp.clear();
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void erase_test_ref (void)
{
std::cout << "erase_test_ref() {" << std::endl;
std::map<std::string, A&> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A&>("key2", a));
auto f = mp.find("key2");
if (f == mp.end()) {
std::cout << "failed to find element {" << std::endl;
return;
}
mp.erase(f);
std::cout << "}" << std::endl;
std::cout << std::endl;
}
int main ()
{
clear_test_value();
erase_test_value();
clear_test_ptr();
erase_test_ptr();
clear_test_ref();
erase_test_ref();
return (0);
}
Output:
clear_test_value() {
A(A1 data) #0x7ffee07389a0
Copy A(A1 data) #0x7ffee0738960
Copy A(A1 data) #0x7fe98fc029c8
Destruct ~A(A1 data) #0x7ffee0738960
Destruct ~A(A1 data) #0x7fe98fc029c8
}
Destruct ~A(A1 data) #0x7ffee07389a0
erase_test_value() {
A(A1 data) #0x7ffee07387f0
Copy A(A1 data) #0x7ffee07387b0
Copy A(A1 data) #0x7fe98fc029c8
Destruct ~A(A1 data) #0x7ffee07387b0
Destruct ~A(A1 data) #0x7fe98fc029c8
}
Destruct ~A(A1 data) #0x7ffee07387f0
clear_test_ptr() {
A(A1 data) #0x7ffee07389b0
}
Destruct ~A(A1 data) #0x7ffee07389b0
erase_test() {
A(A1 data) #0x7ffee0738800
}
Destruct ~A(A1 data) #0x7ffee0738800
clear_test_ref() {
A(A1 data) #0x7ffee07389b0
}
Destruct ~A(A1 data) #0x7ffee07389b0
erase_test_ref() {
A(A1 data) #0x7ffee0738800
}
Destruct ~A(A1 data) #0x7ffee0738800