Ответ 1
Память - это память. Объект в С++ занимает некоторое место в памяти; это местоположение может находиться в стеке или в куче, или оно может быть статически распределено. Не имеет значения, где находится объект: любой поток, который имеет ссылку или указатель на объект, может получить доступ к объекту. Если два потока имеют ссылку или указатель на объект, то оба потока могут получить к нему доступ.
В вашей программе вы создаете рабочий поток (путем создания std::thread
), который выполняет предоставленное им лямбда-выражение. Поскольку вы фиксируете как stackObj
, так и heapObj
по ссылке (используя по умолчанию [&]
захват по умолчанию), эта лямбда имеет ссылки на оба этих объекта.
Эти объекты расположены в стеке основного потока (обратите внимание, что heapObj
- объект типа указателя, который находится в стеке основного потока и указывает на динамически выделенный объект, расположенный в куче). Никаких копий этих объектов не производится; скорее, ваше лямбда-выражение имеет ссылки на объекты. Он напрямую изменяет stackObj
и косвенно косвенно изменяет объект, на который указывает heapObj
.
После того, как основной поток присоединяется к рабочему потоку, оба heapObj->x
и stackObj.x
имеют значение 1
.
Если вы использовали значение захвата значения по умолчанию ([=]
), ваше выражение лямбда было бы скопировано как stackObj
, так и heapObj
. Выражение stackObj.x++
в выражении лямбда увеличило бы копию, а stackObj
, которую вы объявляете в main()
, остался бы неизменным.
Если вы фиксируете значение heapObj
по значению, копируется только сам указатель, поэтому, пока используется копия указателя, он все равно указывает на тот же динамически выделенный объект. Выражение heapObj->x++
приведет к разыменованию этого указателя, создав Obj
, созданный с помощью new Obj()
, и увеличит его значение. Затем вы наблюдали в конце main()
, что heapObj->x
был увеличен.
(Обратите внимание, что для изменения объекта, захваченного значением, выражение lambda должно быть объявлено mutable
.)