I have a regular method that sometimes takes too long. There is a request to implement this method differently and to exit on timeout. Unfortunately the procedure cannot be interrupted, so it has to be finished, but I can return from the function leaving the procedure running in a separate thread. I've implemented it using a packaged_task pattern:
int mayTakeTooLong() {
auto asyncProcedure = []() -> int {
// Old code is here
};
std::packaged_task<int()> task(std::move(asyncProcedure));
auto future = task.get_future();
std::thread workerThread(task);
switch (future.wait_for(std::chrono::seconds(1))) {
case std::future_status::ready:
workerThread.join();
return future.get();
case std::future_status::timeout:
workerThread.detach();
return 0;
}
}
Disregard for now the fact that I'm detaching the thread in case of a timeout: in actual implementation trickier.
Now imagine that there is a parameter of the function that is passed by reference:
int mayTakeTooLong(const std::vector<SomeClass> &values);
Due to the fact the asyncProcedure may run longer than the lifetime of the vector, I need to copy it somewhere. My first implementation [I guess] was incorrect. I was passing the vector by value to the lambda itself:
int mayTakeTooLong() {
auto asyncProcedure = [](std::vector<SomeClass> values) -> int {
// Old code is here
};
std::packaged_task<int(std::vector<SomeClass>)> task(std::move(asyncProcedure));
auto future = task.get_future();
std::thread workerThread(task, values);
// ...
}
The problem with this code is that the values are copied asynchronously and not in the constructor of the thread, being synchronized with the beginning of the invocation of the lambda. So the first question is whether my understanding is correct.
A more safe idea is to capture the object into the lambda:
int mayTakeTooLong(const std::vector<SomeClass> &values) {
auto asyncProcedure = [values]() -> int {
// Old code is here
};
// ...
}
The values are being copied by value and become the part of the lambda. But in this case each time the lambda is being copied itself the vector would be copied as well. I'm trying to prevent the copying be moving the lambda:
int mayTakeTooLong(const std::vector<SomeClass> &values) {
auto asyncProcedure = [values]() -> int {
// Old code is here
};
std::packaged_task<int()> task(std::move(asyncProcedure));
// ...
}
As I can see, the lambda is never copied, but is that guaranteed by the standard? What could be a better option to implement this pattern?
Related
I have a nested lambda in C++, which is to say, an inner lambda contained in a middle lambda, which is also contained in an outer lambda.
I created a shared_ptr in the outer lambda, which I passed by value to the middle lambda, inside which I created the inner lambda, after declaration of which the captured shared_ptr seems to be released, as can be confirmed with use_count() turning into zero. Why?
The full code:
#include <cstdio>
#include <functional>
#include <memory>
struct container;
using func_type = std::function<void(container&)>;
struct container {
explicit container(int id, func_type next) : id{id}, next{next} {
printf("contianer (%d)\n", id);
}
func_type next;
int id;
~container() {
printf("~contianer (%d)\n", id);
}
};
struct value_type {
~value_type() {
printf("~value_type\n");
}
};
int main() {
container c{0, [](container& c1) {
std::shared_ptr<value_type> value = std::make_shared<value_type>();
c1 = container{1, [value](container& c2) mutable {
printf("value.use_count(): %d\n", value.use_count());
c2 = container{2, [](container& c3) mutable {
printf("finished\n");
return;
}};
printf("value.use_count(): %d\n", value.use_count());
return;
}};
return;
}};
c.next(c);
c.next(c);
return 0;
}
Output: (godbolt: https://godbolt.org/z/9PbboEPfK)
Program returned: 0
Program stdout
contianer (0)
contianer (1)
~contianer (1)
value.use_count(): 1
contianer (2)
~value_type
~contianer (2)
value.use_count(): 0
~contianer (2)
When you call c.next(c) the first time, you are running the function c.next which will cause c.next to be replaced by a new lambda, the one that owns a shared pointer. After the first c.next(...) call this shared_ptr owning lambda will be the new c.next.
When you then call c.next(c) again you are replacing that lambda with one that has no ownership of the shared_ptr so the shared_ptr gets destructed as it should when the replacement assignment happens as nothing else has a reference to it except a closure that is going out of scope.
If this was real code -- which I mean if it's real code, do not do whatever you are doing this way -- you could get the behavior you seem to want by having the inner lambda, the one that just prints "finished", also capture value.
I am using lambdas to initialize some const variables as described in the core c++ guidelines here. In short, the idiom looks like this
const auto a = [&]() {
MyType a;
// complex initialization
return a;
}();
The problem arises when the initialization can throw an exception that can only be handled outside of the lambda, eg because it must cause the function to return early. I want to be able to do something that looks like this
try {
const auto a = [&]() {
MyType a;
// complex initialization
return a;
}();
}
catch { /* doesn't matter what */ } {
// Somehow handle it
// then return or throw
}
// use a
except that I want the object to be usable after the try-catch block when an exception is not thrown.
I could refactor the function so that all code that depends on successful initialization of the object is inside the try block but this scales horribly with multiple objects to initialize.
try {
const auto a = ...;
try {
const auto b = ...;
try...
catch...
}
catch {...} {
...;
}
catch {...} {
...;
}
On the other hand, moving the try-catch block inside the lambda restricts what I can do to handle it. eg it does not allow me to instantly return, break or continue as far as I can tell. It almost feels like the logical solution would be to interleave the assignment with the try block (eg const auto a = try [&]()...) but it does not seem to be supported by the anguage. Am I correct in that this is not supported and if so is there another known idiom that would result in the behavior I need?
Note: I am asking for situations where it is important for the variable to be const or where default construction followed by assignment is impossible so the obvious solution of default constructing outside the try-block and assigning the value inside it is not viable.
It is honestly no different from simple initialization which also may throw. Try not to micro manage your exceptions. Their power is in allowing you to code freely without worrying about errors every single statement. Put all of the code that does a complete job (or operation) in your try{}catch(){}. An exception should abort the whole procedure, not just a single initialization.
try
{
const auto a = [&]() {
MyType a;
// complex initialization
return a;
}();
const auto b = "something else that may throw"s;
const auto c = a_throwing_function();
// Now do stuff with a, b and c safe in the knowledge that
// they are properly constructed and valid
// ... etc ...
}
catch(std::exception const& e)
{
// abort the entire operation
}
I'm using some (somewhat C-ish) library which involves a callback mechanism. The callback functions I can provide it take a void* as a parameter so you can pass arbitrary stuff to them. For the sake of this question let's assume the lambda doesn't take any parameters, but it does capture stuff.
Now, I need to have my callback function invoke a lambda - and it must get this lambda somehow via the void *, i.e. we have
void my_callback(void * arbitrary_stuff) {
/* magic... and somehow the lambda passed */
/* through `arbitrary_stuff` is invoked. */
}
// ...
template <T>
void adapted_add_callback(MagicTypeInvolvingT actual_callback) {
/* more magic */
libFooAddCallback(my_callback, something_based_on_actual_callback);
}
// ...
void baz();
void bar() {
int x;
adapted_add_callback([x]() { /* do something with x */ });
adapted_add_callback(baz);
}
and I want to know what to replace magic, more_magic and MagicTypeInvolvingT with.
Other than the typing challenge here, what I'm worried about, obviously, is how to make sure the data the lambda encapsulates is available on the stack for eventual use, as otherwise I should probably get some kind of segmentation fault.
Notes:
my_callback() should be synchronous, in the sense that it'll execute the lambda on whatever thread it is on and return when it returns. It's either the fooLibrary or the lambda itself which do asynchronicity.
the most straightforward way might be ( assuming the C function is guaranteed to invoke the callback exactly once, and that the lambda is valid at callback point )
void my_callback(void * arbitrary_stuff) {
(*std::unique_ptr{ static_cast<std::function<void()>*>(arbitrary_stuff) })();
}
void adapted_add_callback( std::function<void()> actual_callback ) {
libFooAddCallback(my_callback, new auto( std::move(actual_callback) ) );
}
if you don't want the function<> overhead you'll need to implement your own type erasure ...
You have a couple of issues here.
One is that you can't depend on passing the lambda itself as a void *, so you'll pretty much need to pass a pointer to the lambda (well, the closure created from the lambda, if you want to be precise). That means you'll need to ensure that the lambda remains valid until the callback completes.
The second is a question about how those captures happen - capture by value, or by reference? If you capture by value, everything's fine. If you capture by reference, you also need to ensure that anything you've captured remains valid until the callback completes. If you capture a global by reference, that should normally be fine--but if you capture a local by reference, then the local (even potentially) goes out of scope before the lambda is invoked, using the reference will cause undefined behavior.
I went in a way similar to Massimiliano Janes', but without the overhead of std::function. You have to ensure that the callback is called only once by the library.
using Callback = void(*)(void*);
// Probes the type of the argument and generates a suitable cast & invoke stub
// Caution: self-destructs after use!
template <class F>
Callback cbkWrap(F &) {
return [](void *data) {
std::unique_ptr<F> retrieved(static_cast<F*>(data));
(*retrieved)();
};
}
// Moves the functor into a dynamically-allocated one
template <class F>
void *cbkFunc(F &f) {
return new F{std::move(f)};
}
int main() {
int x = 42;
auto lambda = [&x] { std::cout << x << '\n'; };
libFooAddCallback(cbkWrap(lambda), cbkFunc(lambda));
}
See it live on Coliru
If you can ensure that the lambda outlives the potential calls, you can get rid of the dynamic memory allocations and simply pas a pointer to it as data:
// Probes the type of the argument and generates a suitable cast & invoke stub
template <class F>
Callback cbkWrap(F &) {
return [](void *data) {
auto retrieved = static_cast<F*>(data);
(*retrieved)();
};
}
int main() {
int x = 42;
auto lambda = [&x] { std::cout << x << '\n'; };
libFooAddCallback(cbkWrap(lambda), &lambda);
}
See it live on Coliru
There is unfortunately no way to give ownership of the lamba to the library without knowing exactly how many times it will be called.
As far I know, after running the following code myString should have got the value "Inside lambda3.secondLambda". Instead it will still have the value "Initialized".
std::string myString("Initialized");
auto lambda3 = [&]() { [&myString]() { myString = "Inside lambda3.secondLambda"; }; };
The first lambda captures all variables by reference and the sencond captures only myString by reference. Why does it not behave as I have expected?
By specifying the body of the lambda, you specify code that would be called when the lambda's operator() is called.
So you need to actually call the lambdas, otherwise it's simply code inside the definition of functions which never get called. You can do:
auto lambda3 = [&] {
auto l = [&myString] {
myString = "Inside lambda3.secondLambda";
};
l();
};
lambda3();
To take it one step further, you can return the inner lambda and then execute it like this:
auto lambda3 = [&] {
return [&myString] {
myString = "Inside lambda3.secondLambda";
};
};
lambda3()();
You have defined a closure, but not actually run the function. You must actually run it like lambda3() if you want to execute its body.
However, you have nested lambdas, so you need to run what's in the lambda as well. It's not clear why you are doing this. Your inner lambda is neither assigned inside the outer lambda's scope (so you can run it inside the lambda using the same syntax), or returned (so the caller of this lambda can run what it returns).
If you returned it, you could do lambda3()():
auto lambda3 = [&]() { return [&myString]() { myString = "Inside
lambda3.secondLambda"; }; };
Note: only the word return was added to allow lambda3()() to work.
In this particular example, you are better served with just:
auto lambda3 = [&myString]() {
myString = "Inside lambda3.secondLambda"; };
I want to submit a handle but I only want it to be executed if a shared pointer is still valid:
// elsewhere in the class:
std::shared_ptr<int> node;
// later on:
const std::weak_ptr<int> slave(node); // can I do this in the capture clause somehow?
const auto hook = [=]()
{
if (!slave.expired())
//do something
else
// do nothing; the class has been destroyed!
};
someService.Submit(hook); // this will be called later, and we don't know whether the class will still be alive
Can I declare slave within the capture clause of the lambda? Something like const auto hook = [std::weak_ptr<int> slave = node,=]().... but unfortunately this doesn't work. I would like to avoid declaring the variable and then copying it (not for performance reasons; I just think it would be clearer and neater if I could create whatever the lambda needs without polluting the enclosing scope).
You can do this using generalized lambda captures in C++14:
const auto hook = [=, slave = std::weak_ptr<int>(node)]()
{
...
};
Here's a live example. Note that since there are no parameters or explicit return type, the empty parameter list (()) can be left out.
As mentioned by chris this is possible in C++14.
If you are willing to modify the captured value simply add mutablespecifier.
Here is an example which fills a vector from zero to the length of the vector.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> container(10);
std::generate(container.begin(), container.end(), [n = 0]() mutable { return n++; });
for (const auto & number : container)
{
std::cout << number << " ";
}
std::cin.ignore();
return 0;
}