Perfect forwarding const ref deduction error - c++

I've written a super simple thread wrapper that takes a function and runs it in a thread and provides a simple mechanism to signal the thread when it's time to quit. The start function looks like
//tw.hpp
class ThreadWrapper
{
public:
// ...snipped ...
template<typename... Args>
bool start(Args&& ... args)
{
ft_ = std::async(std::launch::async, std::forward<Args>(args)... );
return true;
}
};
When I use it for a non-member function, I need to pass in a const ref of the wrapper into the function that is running to provide a handle the function can use to know when to quit:
void lone_worker(const ThreadWrapper& tw)
{
while (!tw.is_quit_requested())
{
std::cout << "working hard alone\n";
sleep(1);
}
}
void nonmember_demo()
{
ThreadWrapper tw;
tw.start(&lone_worker, std::cref(tw)); // the cref is need to avoid hundreds of lines of compiler template puke with no useful error messages
sleep(5);
std::cout << "quitting\n";
tw.request_quit();
}
I was caught off guard when I originally compiled it without using std::cref by literally hundreds of lines of compiler template puke (gcc 8.1.0) and no clear reason. Is there something I haven't done right with the perfect forwarding to require the use of cref? I assume it's partially caused by the class being non-copyable (it contains a std::future), which smells a little since at least I assume no copy should be made in the first place.
Full exampl here: https://coliru.stacked-crooked.com/a/0eb4d6160b44764a

which smells a little since at least I assume no copy should be made in the first place
You assume incorrectly. async mostly just forwards to thread, which starts by executing:
std::invoke(decay_copy(std::forward<Function>(f)),
decay_copy(std::forward<Args>(args))...);
This does copy all the arguments. The point of the reference wrapper is to avoid this copy - instead of copying the ThreadWrapper object (which is noncopyable), you're copying a std::reference_wrapper<ThreadWrapper const> (which is copyable).
From the linked cppreference page for thread:
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::ref or std::cref).

Related

Is it possible to create std future with blocking destructor without calling std async?

There is a remark on cppreference about the destructor of std::future that it will block:
it may block if all of the following are true: the shared state was created by a call to std::async, the shared state is not yet ready, and this was the last reference to the shared state.
So, basically if I create future via promise.get_future(), it does not block in destructor.
Is there a way to create an std::future with blocking destructor from std::promise?
Universal Asynchronous Model provides the means to customize behavior of asynchronous methods.
For instance, a completion may be a callable object, which may be a lambda:
async_foo([](){ std::cout << "foo";});
std::cout << "bar";
This will provide barfoo
You can also use a future to get synchronization primitives like std::future.
async_foo(asio::use_future);
std::cout << "bar"; // this line should be invoked only after async_foo has been completed
However, this does not work, since std::future will not block like it will in:
std::async(std::launch::async, &foo);
std::cout << "bar"; // this line will be invoked only after async foo has been completed
You could make a light wrapper for the std::future.
#include <future>
template <typename T>
class MyBlockingFuture {
std::future<T> future;
public:
MyBlockingFuture(std::future<T>&& f) : future(std::move(f)) {}
~MyBlockingFuture() {
if (future.valid()) {
future.wait();
}
}
};
Then add whatever get or wait methods you need.
Making std::future behave this way is not possible without modifying it.
Also note that there is no guarantee that the shared state held by a promise from std::async will block when destructed. The note only says that it may do so.
Blocking a future in a destructor is pretty fraught with danger in the first place, since it can throw an exception.
However even if that's not really your question, in case someone else lands here, it's fairly easy to write a wrapper that would do just that.
template<typename T>
struct FutureWaiter {
~FutureWaiter () { fut_.wait(); }
std::future<T>& fut_;
};
template<typename T>
[[nodiscard]] FutureWaiter<T> scoped_wait(std::future<T>& fut) {
return FutureWaiter<T>{fut};
}
int main() {
std::promise<int> x;
auto fut = x.get_future();
auto wait = scoped_wait(fut);
x.set_value(3);
}
You may want/need to change the ownership semantics a bit depending on your needs, but the principles should remain the same.

Is it safe to pass std::function<bool(std::string)> &&callback (i.e. as a rvalue move) and what is the effect?

Given the following working code (main.cpp):
#include <functional>
#include <iostream>
struct worker
{
std::function<bool(std::string)> m_callback;
void do_work(std::function<bool(std::string)> callback) // <--- this line
{
m_callback = std::bind(callback, std::placeholders::_1);
callback("hello world!\n");
}
};
// pretty boring class - a cut down of my actual class
struct helper
{
worker the_worker;
bool work_callback(std::string str)
{
std::cout << str << std::endl;
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work( [&](std::string data){ return the_helper.work_callback(data); });
}
Compiled with: -std=c++11 -O2 -Wall -Wextra -pedantic-errors -O2 main.cpp
I have comment the line in question (<-- this line - around line 7), where I think it would be more efficient to use: void do_work(std::function<bool(std::string)>&& callback) i.e. using the && move semantic.
I have never really used this, mostly because I still don't quite understand it.
My understanding is this:
void do_work(std::function<bool(std::string)> callback) - will take a copy of the lambda that I pass in (which is an rvalue I think).
void do_work(std::function<bool(std::string)> callback) - will move the lambda that I pass in because it is an rvalue.
My crude idea of an rvalue is any temporary variable.
Questions:
What I am not 100% clear about is, is what I wrote correct? and therefore is it safe to use &&. Both seem to work.
Does this && method also work if instead of passing a lambda like this:
the_helper.the_worker.do_work( [&](std::string data){ return the_helper.work_callback(data); });
we pass in std::bind(...):
the_worker.do_work(std::bind(&helper::work_callback, the_helper, std::placeholders::_1));
If the parameter is defined as an rvalue-reference, you must pass a temporary or cast an lvalue to an rvalue, like with std::move().
And the semantics of rvalue-references are that the caller should expect the passed argument to be plundered, rendering it valid but arbitrary, meaning mostly useless.
But the function receiving an rvalue-reference, despite having license to plunder, does not have any obligation to plunder. And if it doesn't explicitly do so, for example by passing that license on, then it doesn't come to pass, and nothing special happens.
Your code is such a case.
While I would ban std::bind from my vocabulary, using it or not doesn't actually make any significant difference.
In this case regardless of whether you pass by value or by rval ref a temporary std::function will have to be created, that's because a lambda is not really a std::function. In any case, you should move the std::function before assigning, to avoid making an unnecessary copy.
I'd recommend passing by value in this case, as this is a bit more flexible, and if you are passing lambdas, then it does not cause any harm, as the std::function will usually be constructed in place (so the temporary will not be moved into the function; this move can, and usually will, be elided).

Universal references in a thread function

I have been learning about perfect forwarding and the use of && in function templates (see this previous question of mine) and would like to know if my use of Args&& in StartDetachedThread() below is justified:
#include <thread>
class CObject {};
void MyThreadFunc(CObject&)
{
}
// ** Will not compile with this function declaration! **
void MyThreadFunc(CObject&&)
{
}
template<typename FunctionType, typename ...Args>
void StartDetachedThread(FunctionType func, Args&&... args)
{
thread([&]()
{
func(forward<Args>(args)...);
}).detach();
}
int main()
{
CObject object;
StartDetachedThread(MyThreadFunc, object);
CObject object2;
StartDetachedThread(MyThreadFunc, std::move(object2));
return 0;
}
This code simply creates a detached thread, running the supplied function passing to it the supplied arguments.
Hhowever, VS 2017 complains:
'StartDetachedThread': no matching overloaded function found
'void StartDetachedThread(FunctionType,Args &&...)': could not deduce template argument for 'FunctionType'
1) I know that arguments passed to the thread constructor are copied first, then passed by reference to the new thread, so is my attempt to have MyThreadFunc(CObject&&) called when I pass an rvalue reference never going to work?
2) Is there any value in having StartDetachedThread(FunctionType&& func, Args&&... args) - or is the && unnecessary for FunctionType?
3) Is there any value whatsoever in using Args&& when starting a thread like this, or should I always use Args?
The problem in your code has nothing to do with std::thread, it is because MyThreadFunc is ambiguous in this context:
// Which MyThreadFunc should be used?
StartDetachedThread(MyThreadFunc, object);
Regarding your question:
1) I know that arguments passed to the thread constructor are copied first, then passed by reference to the new thread, [...]
In your example, the only copy is the copy of the lambda. The arguments are not copied here, if you want the argument to be copied you should use something like this:
std::thread(std::move(func), std::forward<Args>(args)...).detach();
...where you forward the arguments to std::thread constructor.
This is safer. — Think about what happens if the function StartDetachedThread ends while the thread is still running?
If you use this, you need to explicitly tell the compiler you want to call the reference version for object1 by using std::ref:
CObject object;
StartDetachedThread<void (CObject&)>(MyThreadFunc, std::ref(object)); // std::ref
CObject object2;
StartDetachedThread<void (CObject&&)>(MyThreadFunc, std::move(object2));
2) Is there any value in having StartDetachedThread(FunctionType&& func, Args&&... args) - or is the && unnecessary for FunctionType?
3) Is there any value whatsoever in using Args&& when starting a thread like this, or should I always use Args?
Using forwarding references allows you to call StartDetachedThread without having to move everything. If you use the above way for constructing a std::thread, then copies will be made for func and args anyway.
The issue is that which overload of MyThreadFunc is desired is not deducible by the compiler. There are at least two ways to fix it:
Rename one of the function so that it is clearer which one you want.
Use explicit template parameters:
StartDetachedThread<void (CObject&)>(MyThreadFunc, object);
StartDetachedThread<void (CObject&&)>(MyThreadFunc, std::move(object2));

Can this technique for creating a container of heterogenous functors be salvaged?

This blog post describes a technique for creating a container of heterogeneous pointers. The basic trick is to create a trivial base class (i.e. no explicit function declarations, no data members, nothing) and a templated derived class for storing std::function<> objects with arbitrary signatures, then make the container hold unique_ptrs to objects of the base class. The code is also available on GitHub.
I don't think this code can be made robust; std::function<> can be created from a lambda, which might include a capture, which might include a by-value copy of a nontrivial object whose destructor must be called. When the Func_t type is deleted by unique_ptr upon removal from the map, only its (trivial) destructor will be called, so the std::function<> objects never get properly deleted.
I've replaced the use-case code from the example on GitHub with a "non-trivial type" that is then captured by value inside a lambda and added to the container. In the code below, the parts copied from the example are noted in comments; everything else is mine. There's probably a simpler demonstration of the problem, but I'm struggling a bit to even get a valid compile out of this thing.
#include <map>
#include <memory>
#include <functional>
#include <typeindex>
#include <iostream>
// COPIED FROM https://plus.google.com/+WisolCh/posts/eDZMGb7PN6T
namespace {
// The base type that is stored in the collection.
struct Func_t {};
// The map that stores the callbacks.
using callbacks_t = std::map<std::type_index, std::unique_ptr<Func_t>>;
callbacks_t callbacks;
// The derived type that represents a callback.
template<typename ...A>
struct Cb_t : public Func_t {
using cb = std::function<void(A...)>;
cb callback;
Cb_t(cb p_callback) : callback(p_callback) {}
};
// Wrapper function to call the callback stored at the given index with the
// passed argument.
template<typename ...A>
void call(std::type_index index, A&& ... args)
{
using func_t = Cb_t<A...>;
using cb_t = std::function<void(A...)>;
const Func_t& base = *callbacks[index];
const cb_t& fun = static_cast<const func_t&>(base).callback;
fun(std::forward<A>(args)...);
}
} // end anonymous namespace
// END COPIED CODE
class NontrivialType
{
public:
NontrivialType(void)
{
std::cout << "NontrivialType{void}" << std::endl;
}
NontrivialType(const NontrivialType&)
{
std::cout << "NontrivialType{const NontrivialType&}" << std::endl;
}
NontrivialType(NontrivialType&&)
{
std::cout << "NontrivialType{NontrivialType&&}" << std::endl;
}
~NontrivialType(void)
{
std::cout << "Calling the destructor for a NontrivialType!" << std::endl;
}
void printSomething(void) const
{
std::cout << "Calling NontrivialType::printSomething()!" << std::endl;
}
};
// COPIED WITH MODIFICATIONS
int main()
{
// Define our functions.
using func1 = Cb_t<>;
NontrivialType nt;
std::unique_ptr<func1> f1 = std::make_unique<func1>(
[nt](void)
{
nt.printSomething();
}
);
// Add to the map.
std::type_index index1(typeid(f1));
callbacks.insert(callbacks_t::value_type(index1, std::move(f1)));
// Call the callbacks.
call(index1);
return 0;
}
This produces the following output (using G++ 5.1 with no optimization):
NontrivialType{void}
NontrivialType{const NontrivialType&}
NontrivialType{NontrivialType&&}
NontrivialType{NontrivialType&&}
NontrivialType{const NontrivialType&}
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
Calling NontrivialType::printSomething()!
Calling the destructor for a NontrivialType!
I count five constructor calls and four destructor calls. I think that indicates that my analysis is correct--the container cannot properly destroy the instance it owns.
Is this approach salvageable? When I add a virtual =default destructor to Func_t, I see a matching number of ctor/dtor calls:
NontrivialType{void}
NontrivialType{const NontrivialType&}
NontrivialType{NontrivialType&&}
NontrivialType{NontrivialType&&}
NontrivialType{const NontrivialType&}
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
Calling NontrivialType::printSomething()!
Calling the destructor for a NontrivialType!
Calling the destructor for a NontrivialType!
... so I think this change might be sufficient. Is it?
(Note: the correctness--or lack thereof--of this approach is independent of whether the idea of a container of heterogeneous functions is a good idea. In a few very specific cases, there may be some merit, for instance, when designing an interpreter; e.g., a Python class may be thought of as just such a container of heterogeneous functions plus a container of heterogeneous data types. But in general, my decision to ask this question does not indicate that I think this is likely to be a good idea in very many cases.)
This is basically someone trying to implement type erasure and getting it horribly wrong.
Yes, you need a virtual destructor. The dynamic type of the thing being deleted is obviously not Func_t, so it's plainly UB if the destructor isn't virtual.
The whole design is completely broken, anyway.
The point of type erasure is that you have a bunch of different types that share a common characteristic (e.g. "can be called with an int and get a double back"), and you want to make them into a single type that has that characteristic (e.g., std::function<double(int)>). By its nature, type erasure is a one-way street: once you have erased the type, you can't get it back without knowing what it is.
What does erasing something down to an empty class mean? Nothing, other than "it's a thing". It's a std::add_pointer_t<std::common_type_t<std::enable_if_t<true>, std::void_t<int>>> (more commonly known as void*), obfuscated in template clothing.
There are plenty of other problems with the design. Because the type was erased into nothingness, it had to recover the original type in order to do anything useful with it. But you can't recover the original type without knowing what it is, so it ends up using the type of arguments passed to Call to infer the type of the thing stored in the map. That is ridiculously error-prone, because A..., which represents the types and value categories of the arguments passed to Call, is highly unlikely to match exactly the parameter types of std::function's template argument. For instance, if you have a std::function<void(int)> stored in there, and you tried to call it with a int x = 0; Call(/* ... */ , x);, it's undefined behavior. Go figure.
To make it worse, any mismatch is hidden behind a static_cast that causes undefined behavior, making it harder to find and fix. There's also the curious design that requires the user to pass a type_index, when you "know" what the type is anyway, but it's just a sideshow when compared to all the other problems with this code.

Why is it impossible to move a variable to another std::thread

What is the reason that you can't move an object to another std::thread? There are situations where it could be useful. For example:
You create a loop that accepts incoming socket connections. It would be nice to move incoming connections to another thread that will handle the connections. You don't need the connection anymore in the accept loop. So why should you create a pointer?
A small test case:
#include <iostream>
#include <thread>
using namespace std;
class Pointertest
{
public:
Pointertest() {cout << "Constructor";}
Pointertest(Pointertest &pointertest) {cout << "Copy";}
Pointertest(Pointertest &&pointertest) {cout << "Move";}
~Pointertest() {cout << "Destruct";}
};
void foo(Pointertest &&pointertest)
{
}
int main()
{
Pointertest pointertest;
foo(std::move(pointertest)); //Works
thread test(foo,std::move(pointertest)); //**cannot convert parameter 1 from 'Pointertest' to 'Pointertest &&'**
}
The std::thread constructor has to treat the arguments you give it somewhat differently from most forwarding functions.
The reason for this is due to questions of when the thread actually gets started. If the part of the function invocation that actually created the function argument gets run long after the thread object is created (which is entirely legal behavior), then the object that needs to be moved from may have long since been destroyed.
Just consider an altered version of your code:
std::thread some_func()
{
Pointertest pointertest;
thread test(foo,std::move(pointertest));
return test;
}
This is perfectly valid (the thread will be moved out of the function). However, there's a big problem. foo may not have been called yet. And since foo takes its parameter by reference, it now has a reference to a stack variable that has been destroyed.
That's bad. But even if foo took its parameter by value, it would change nothing. Because the actual movement into that parameter doesn't happen until some indeterminate time after the thread has been started. The attempt to move into the parameter will still use an rvalue reference to a stack variable that has been destroyed. Which again is bad.
Therefore, std::thread constructor does something different. It copy/moves the arguments you give it into internal storage (this is done on the current thread). Then it uses those values as arguments for the actual function call (this is done on the new thread).
According to the standard, the thread constructor should treat pass these internal variables to your functions as temporaries. The standard specifically states INVOKE (DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...), where the DECAY_COPY stuff happens on the original thread, while the INVOKE part happens on the new thread.
So it seems like your thread implementation isn't able to forward the non-copyable parameters through correctly. You should be able to pass a non-copyable type; the arguments are only required to be MoveConstructible.
So this would appear to be a bug in your implementation.
It is possible. Fixing the signature of your copy constructor makes it work for me:
class Pointertest
{
public:
Pointertest() {cout << "Constructor";}
Pointertest(Pointertest const& pointertest) {cout << "Copy";}
// ^^^^^^
Pointertest(Pointertest &&pointertest) {cout << "Move";}
~Pointertest() {cout << "Destruct";}
};
Also, do not forget to join your thread (or detach from it) before your thread object goes out of scope:
int main()
{
Pointertest pointertest;
thread test(foo, std::move(pointertest));
test.join();
// ^^^^^^^^^^^^
}