This code prints 0 (with no optimization) or 666 (with optimizations turned on) when built with clang++ -std=c++11 (-O3 yields 666, which is what I would expect). When lambda is passed by universal reference the problem disappears.
FYI, GCC prints 666 on all the versions I've tested.
Is it a compiler bug or the code is incorrect?
#include <memory>
#include <iostream>
template <typename T>
std::shared_ptr<void> onScopeExit(T f)
{
return std::shared_ptr<void>((void*)1, [&](void *) {
f();
});
}
struct A {
void f() {
auto scopeGuard = onScopeExit([&]() { i = 666; }); // [1]
// ... (some work)
} // (lambda [1] being ? called on scope exit)
int i = 0;
};
A a;
int main() {
a.f();
std::cout << a.i << std::endl;
}
The compiler in question is:
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.7.0
Your code has undefined behavior. You capture f by reference in onScopeExit but once you return the shared_ptr from the function the deleter is now holding a dangling reference to f, since f went out of scope. What you need to do is capture f by value, and then you won't have a dangling reference
template <typename T>
std::shared_ptr<void> onScopeExit(T f)
{
return std::shared_ptr<void>((void*)1, [=](void *) {
f();
});
}
struct A {
void f() {
auto scopeGuard = onScopeExit([&]() { i = 666; }); // [1]
// ... (some work)
} // (lambda [1] being ? called on scope exit)
int i = 0;
};
A a;
int main() {
a.f();
std::cout << a.i << std::endl;
}
Related
Consider this:
#include <iostream>
#include <functional>
std::function<void()> task;
int x = 42;
struct Foo
{
int& x;
void bar()
{
task = [=]() { std::cout << x << '\n'; };
}
};
int main()
{
{
Foo f{x};
f.bar();
}
task();
}
My instinct was that, as the actual referent still exists when the task is executed, we get a newly-bound reference at the time the lambda is encountered and everything is fine.
However, on my GCC 4.8.5 (CentOS 7), I'm seeing some behaviour (in a more complex program) that suggests this is instead UB because f, and the reference f.x itself, have died. Is that right?
To capture a member reference you need to utilize the following syntax (introduced in C++14):
struct Foo
{
int & m_x;
void bar()
{
task = [&l_x = this->m_x]() { std::cout << l_x << '\n'; };
}
};
this way l_x is an int & stored in closure and referring to the same int value m_x was referring and is not affected by the Foo going out of scope.
In C++11 we can workaround this feature being missing by value-capturing a pointer instead:
struct Foo
{
int & m_x;
void bar()
{
int * p_x = &m_x;
task = [=]() { std::cout << *p_x << '\n'; };
}
};
You can capture a reference member in C++11 by creating a local copy of the reference and explicit capture to avoid capturing this:
void bar()
{
decltype(x) rx = x; // Preserve reference-ness of x.
static_assert(std::is_reference<decltype(rx)>::value, "rx must be a reference.");
task = [&rx]() { std::cout << rx << ' ' << &rx << '\n'; }; // Only capture rx by reference.
}
I am unsure about a possible GCC bug in initialization of a std::function from a lambda function capturing this in a non-static data member initializer. Is this allowed by the C++ standard or is this UB?
Given the following code:
#include <functional>
#include <iostream>
template <typename T>
struct A {
T x = 0;
std::function<void(T)> f = [this](T v) { x = v; };
};
int main() {
A<int> a;
a.f(1);
std::cout << a.x << "\n";
}
In my understanding, it should print 1. However, when built with GCC 5.4.0 or GCC 6.2.0, a.f(1) emits a segmentation fault, because the captured this pointer is null.
The following alternatives work as I expected:
Using constructor initializer list:
template <typename T>
struct B {
B() : f([this](T v) { x = v; }) {}
T x = 0;
std::function<void(T)> f;
};
Without template:
struct C {
int x = 0;
std::function<void(int)> f = [this](int v) { x = v; };
};
Also, when built with Clang 3.8.0, all three versions behave as I expect, which doesn't mean it is not UB.
You cannot do:
template <typename T>
struct A {
T x = 0;
std::function<void(T)> f = [this](T v) { x = v; };
};
As this does not exist when you define f. You need to initilize f in a constructor, such as:
A(){ f = [this](T v){ x=v; } }
It worked with G++4.8.
Your code compiles and runs on VS2015 (windows).
So this is probably a compiler error.
Also, if you will remove the template it works on http://cpp.sh/
Try this code:
#include <functional>
#include <iostream>
struct A {
int x = 0;
std::function<void(int)> f = [this](int v) { x = v; };
};
int main() {
A a;
a.f(1);
std::cout << a.x << "\n";
}
running original code on cpp.sh gives:
internal compiler error: in tsubst_copy, at cp/pt.c:12569
Please submit a full bug report
So I guess it's a bug
#include<iostream>
#include<vector>
struct Foo
{
int *nb;
Foo() :nb(new int(5)){}
~Foo(){ delete nb; }
Foo(Foo&& f)
{
std::cout << "Move\n";
nb = f.nb;
f.nb = 0;
}
};
std::vector<Foo> vec;
void func()
{
vec.push_back(Foo());
}
int main()
{
func();
std::cout << *(vec[0]).nb << "\n";
std::cin.ignore();
}
Running:
> ./a.out
Move
5
Is it normal that under VS2013 vec.push_back(Foo()); call Foo(Foo&& f) ?
I believed that Foo() was a lvalue.
This is normal. Since the instance that you create by calling Foo() is never assigned to a variable, the compiler will treat it as an r-value.
A short rule of thumb is that any object you create that is not given a name (ie no declaration) will be an r-value.
For a nice explanation of the details I recommend section 6.4.1 in The C++ Programming Language (4th Edition).
I have a function foo that returns a future. foo will register a callback which will be called after foo returns.
future<int> foo() {
promise<int> p;
future<int> ret(p.get_future());
thread(bind([] (promise<int> &&p) {
this_thread::sleep_for(chrono::seconds(3));
p.set_value(10);
}, move(p))).detach();
return move(ret);
}
int main()
{
auto f = foo();
cout << f.get() << endl;
return 0;
}
But it seems like that std::bind forwards the rvalue reference as a lvalue reference so that can not be successfully compiled. Is there any way to fix it?
I have to write an ugly class to move the promise object:
template<typename T>
class promise_forward {
promise<T> promise_;
public:
promise_forward(promise<T> &&p) :
promise_(move(p)) {}
promise_forward(promise_forward<T> &&other) :
promise_(move(other.promise_)) {}
operator promise<T> () {
return move(promise_);
}
};
future<int> foo() {
promise<int> p;
future<int> ret(p.get_future());
thread(bind([] (promise<int> &&p) {
this_thread::sleep_for(chrono::seconds(3));
p.set_value(10);
}, promise_forward<int>(move(p)))).detach();
return ret;
}
int main()
{
auto f = foo();
cout << f.get() << endl;
return 0;
}
You, basically, doesn't need std::bind here (well , I believe so =)).
Here is a quick draft of a simplest async task launcher. It almost same as yours, but, just a little more generic: it can accept any function objects and it is less intrusive: function objects doesn't know nothing about promises or threading at all.
There are may be mistakes (I'm quite sure they are). And, of course, it is far far away, from std::async implementation (which, generally, more than just thread launcher, but, ideally, have a huge thread management back-end).
#include <thread>
#include <future>
#include <iostream>
#include <chrono>
template< class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type> my_async(Function && f, Args && ... args)
{
typedef typename std::result_of<Function(Args...)>::type ret_type;
std::promise<ret_type> p;
auto fut = p.get_future();
// lambda in separate variable, just to improve readability
auto l = [](Function && f, Args && ... args, std::promise<ret_type> && p)
{
p.set_value(f(args...));
};
std::thread th(l, std::move(f), std::move(args...), std::move(p));
th.detach();
return std::move(fut);
}
int wannaRunAsync(int i)
{
return i;
};
int main()
{
auto fut = my_async(&wannaRunAsync, 42);
auto fut2 = my_async([](int i) -> int { return i; }, 42);
std::cout << fut.get() << std::endl;
std::cout << fut2.get() << std::endl;
std::cin.get();
return 0;
}
I was able to compile and run it with
g++-4.8 and
clang++ but with msvc 2012 and 2013 preview it doesn't even compiles (probably, due to errors).
I've not tested this code at all, so be careful =) Hope it helps.
This code generates a SIGSEGV on runtime when compiled with GCC (4.7.2-5ubuntu) but not Clang (Apple LLVM 4.2)
#include <functional>
#include <iostream>
using FuncType = std::function<int(int)>;
int func(FuncType f, int i) {
return f(i)+1;
}
struct Alpha {
FuncType f, g;
Alpha(FuncType f) : f(f) {
g = [&](int i) -> int {
return func(f, i);
};
}
int go(int i) {
return g(i);
}
};
struct Beta {
int k = 0;
Beta newBeta(int nk) {
Beta beta = *this;
beta.k = nk;
return beta;
}
};
struct Gamma {
Beta beta;
void go(int j) {
auto f = [&](int i) -> int {
int n = beta.newBeta(i).k+j;
return n*n;
};
Alpha alpha(f);
std::cout << alpha.go(beta.k) << std::endl;
}
};
int main(int argc, char *argv[]) {
Gamma gamma;
gamma.go(7);
return 0;
}
Debugging, the crash occurs when the lambda f is called in func. beta reports as an invalid object, even though it should still be valid when the lambda is called.
It looks as though this is a result of this bug, but that bug was reportedly fixed in 4.7.2.
Edit: Initialized Beta::k for clarity, does not affect bug.
One problem is here:
Alpha(FuncType f) : f(f) {
g = [&](int i) -> int {
return func(f, i);
};
}
your lambda is binding f (an argument to the contructor and so local to the constructor) by reference, so after the constructor completes, that reference is dangling. When you later call g, you get undefined behavior as it refers to this dangling reference.
Change the [&] to [=] to bind by value and it should be ok.