Is passing a const reference variable to a thread function using const reference wrapper redundant/unnecessary? The below code works with and without std::cref
#include <iostream>
#include <string>
#include <future>
bool thread_func(const std::string& str) {
std::cout << str << std::endl;
return true;
}
int main() {
const std::string a{"ABCDE"};
const std::string& a_ref = a;
// is wrapping a_ref inside a const reference_wrapper redundant in the below code?
const std::future<bool> res1 = std::async(std::launch::async, thread_func, std::cref(a_ref));
const std::future<bool> res2 = std::async(std::launch::async, thread_func, a_ref);
res1.wait();
res2.wait();
}
reference arguments to thread function
No, it is not redundant.
You should definitely use std::ref / std::cref if you want to pass an argument by reference to a thread (and keep reference semantics).
This is because the arguments for a thread are always copied (or moved if applicable) when the thread is created.
Therefore, a "normal" reference will not preserve reference semantics, but std::ref/std::cref return a std::reference_wrapper which will preserve it:
std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object.
Your code might seem to work as you expect, but in fact your std::string argument is being copied in the second case (without std::cref) - and I assume this is not what you intended.
This is demonstrated by adding some prints to your code:
#include <iostream>
#include <string>
#include <future>
bool thread_func(int asyncId, const std::string& str) {
std::cout << "thread_func " << asyncId <<
", address: " << &str << " value:" << str << "\n";
return true;
}
int main() {
const std::string a{ "ABCDE" };
const std::string& a_ref = a;
// is wrapping a_ref inside a const reference_wrapper redundant in the below code?
std::cout << "main, address: " << &a_ref << "\n";
const std::future<bool> res1 = std::async(std::launch::async,
thread_func, 1, std::cref(a_ref));
std::cout << "main, address: " << &a_ref << "\n";
const std::future<bool> res2 = std::async(std::launch::async,
thread_func, 2, a_ref);
res1.wait();
res2.wait();
}
Possible output:
main, address: 0000005A8EAFF710
main, address: 0000005A8EAFF710
thread_func 1, address: 0000005A8EAFF710 value:ABCDE
thread_func 2, address: 000001D6958229F8 value:ABCDE
The specific address can change of course, and the prints might mix between the threads, so keep in mind this is only a demonstration.
But, as you can see, in the second std::async call the address of the argument is not the same as the one in main (unlike the first case using std::cref).
Live demo
A side note:
As @RemyLebeau commented below, you cannot take a reference to a reference (because you end up with the same reference to the original object).
Therefore, std::cref(a_ref) is the same as simply std::cref(a), and the same applies when passing it to std::async().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With