Memory is memory. An object in C++ occupies some location in memory; that location may be on a stack or on the heap, or it may have been statically allocated. It doesn't matter where the object is located: any thread that has a reference or pointer to the object may access the object. If two threads have a reference or a pointer to the object, then both threads may access it.
In your program, you create a worker thread (by constructing a std::thread
) that executes the lambda expression you provide it. Because you capture both stackObj
and heapObj
by reference (using the [&]
capture default), that lambda has references to both of those objects.
Those objects are both located on the main thread's stack (note that heapObj
is a pointer-type object that is located on the main thread's stack and points to a dynamically allocated object that is located on the heap). No copies of these objects are made; rather, your lambda expression has references to the objects. It modifies the stackObj
directly and modifies the object pointed to by heapObj
indirectly.
After the main thread joins with the worker thread, both heapObj->x
and stackObj.x
have a value of 1
.
If you had used the value capture default ([=]
), your lambda expression would have copied both stackObj
and heapObj
. The expression stackObj.x++
in the lambda expression would increment the copy, and the stackObj
that you declare in main()
would be left unchanged.
If you capture the heapObj
by value, only the pointer itself is copied, so while a copy of the pointer is used, it still points to the same dynamically allocated object. The expression heapObj->x++
would dereference that pointer, yielding the Obj
you created via new Obj()
, and increment its value. You would then observe at the end of main()
that heapObj->x
has been incremented.
(Note that in order to modify an object captured by value, the lambda expression must be declared mutable
.)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…