Difference between pointer and reference as thread parameter
The constructor of std::thread
deduces argument types and stores copies of them by value. This is needed to ensure the lifetime of the argument object is at least the same as that of the thread.
C++ template function argument type deduction mechanism deduces type T
from an argument of type T&
. All arguments to std::thread
are copied and then passed to the thread function so that f1()
and f2()
always use that copy.
If you insist on using a reference, wrap the argument using boost::ref()
or std::ref()
:
thread t1(f1, boost::ref(ret));
Or, if you prefer simplicity, pass a pointer. This is what boost::ref()
or std::ref()
do for you behind the scene.
C++ Objects: When should I use pointer or reference
A reference is basically a pointer with restrictions (has to be bound on creation, can't be rebound/null). If it makes sense for your code to use these restrictions, then using a reference instead of a pointer allows the compiler to warn you about accidentally violating them.
It's a lot like the const
qualifier: the language could exist without it, it's just there as a bonus feature of sorts that makes it easier to develop safe code.
Multithreading - why working on a reference doesn't change it, while on a pointer works properly
1) Your code is not thread safe (concurrent push_back
on a vector)
2) Arguments are passed by value by default to std::thread
. This semantic of copying the arguments is natural with threads : any argument will be copied/moved to thread-accessible storage. Doing so, the std:::thread
does its best to avoid concurrency access to shared objects.
Use std::ref
to pass an argument by reference to your thread callable :
thread t1(doSomething, std::ref(v));
thread t2(doSomething, std::ref(v));
^^^^^^^^
Without std::ref
, neither gcc or clang compile this code.
For future reference, std::thread
constructors are described in section § 30.3.1.2 of the C++ standard.
When to use references vs. pointers
Use reference wherever you can, pointers wherever you must.
Avoid pointers until you can't.
The reason is that pointers make things harder to follow/read, less safe and far more dangerous manipulations than any other constructs.
So the rule of thumb is to use pointers only if there is no other choice.
For example, returning a pointer to an object is a valid option when the function can return nullptr
in some cases and it is assumed it will. That said, a better option would be to use something similar to std::optional
(requires C++17; before that, there's boost::optional
).
Another example is to use pointers to raw memory for specific memory manipulations. That should be hidden and localized in very narrow parts of the code, to help limit the dangerous parts of the whole code base.
In your example, there is no point in using a pointer as argument because:
- if you provide
nullptr
as the argument, you're going in undefined-behaviour-land; - the reference attribute version doesn't allow (without easy to spot tricks) the problem with 1.
- the reference attribute version is simpler to understand for the user: you have to provide a valid object, not something that could be null.
If the behaviour of the function would have to work with or without a given object, then using a pointer as attribute suggests that you can pass nullptr
as the argument and it is fine for the function. That's kind of a contract between the user and the implementation.
What's the difference between ( this ) and ( std::ref(*this) )
In the context of launching a thread running a member function of a class A
, those calls are equivalent.
The first is like
void compiler_created_on_new_thread(A * a) { a->Func(); }
The second is like
void compiler_created_on_new_thread(A & a) { a.Func(); }
If instead A
were a namespace, they would be distinguishable
namespace A {
void Func(Thing *) { std::cout << "pointer"; }
void Func(Thing &) { std::cout << "reference"; }
}
The first would display "pointer" and the second "reference"
Why are we not allowed to pass pure reference arguments to std::thread but are allowed to pass raw pointers?
What is special in case of passing references ??
The special thing is that passing by reference looks identical at the call site to passing by value.
Every other case you show leaves at least a hint at the call site that you may be doing something risky, without having to read the function prototype.
Why does passing object reference arguments to thread function fails to compile?
Threads copy their arguments (think about it, that's The Right Thing). If you want a reference explicitly, you have to wrap it with std::ref
(or std::cref
for constant references):
std::thread t(foo, std::ref(std::cout));
(The reference wrapper is a wrapper with value semantics around a reference. That is, you can copy the wrapper, and all copies will contain the same reference.)
As usual, this code is only correct as long as the object to which you refer remains alive. Caveat emptor.
Difference between pointer-to-pointer vs reference-to-pointer (C++)
The first example is that of a reference to a pointer, ie. a reference to a type IEnumWbemClassObject*
:
HRESULT Query ( IN BSTR sQuery, OUT IEnumWbemClassObject* &pEnumerator );
Therefore if pEnumerator
is declared as a IEnumWbemClassObject*
(which I'm assuming it is), you don't need to explicitly pass the address of pEnumerator
to the function or dereference the variable inside the function in order to change where pEnumerator
points (which would otherwise be required with an argument of IEnumWbemClassObject**
).
A reference to a pointer has the same behaviour as a reference to any other type, just think of the above example as being a "reference to a pointer" and not a "pointer to a reference." There's no such thing as a pointer to a reference.
Related Topics
How to Read/Write Arbitrary Bits in C/C++
When to Use Std::Forward to Forward Arguments
Checking for Null Pointer in C/C++
Unnecessary Curly Braces in C++
Efficient Way to Determine Number of Digits in an Integer
Convert Float to String with Precision & Number of Decimal Digits Specified
Std::Map Emplace Without Copying Value
How to Find and Replace String
Converting Multidimensional Arrays to Pointers in C++
How to Efficiently Display Opencv Video in Qt
Why Is Stack Memory Size So Limited
C++11: I Can Go from Multiple Args to Tuple, But How to Go from Tuple to Multiple Args
When Is It Best to Use the Stack Instead of the Heap and Vice Versa
Does There Exist a Static_Warning
How to Use Std::Sort to Sort an Array in C++