Ответ 1
Ваша программа неверна; объекты указателя совместного использования не предназначены для синхронизации.
[intro.multithread]/24:
Реализация может предполагать, что любой поток в конечном итоге сделает одно из следующего:
- завершение,
- сделать вызов функции ввода-вывода библиотеки,
- доступ или изменение изменчивого объекта или
- выполнить операцию синхронизации или атомную операцию.
std::weak_ptr::expired()
не является операцией синхронизации или атомной операцией; все Стандарт говорит, что он не вводит гонку данных. Поскольку разрешение дефект библиотеки 2316, std::weak_ptr::lock()
считается атомной операцией, поэтому для ответа 2) ваш код с использованием Ref.lock()
действителен как из С++ 14.
Теперь, правда, если бы вы попытались создать свою собственную библиотечную реализацию weak_ptr
, используя средства языка и библиотеки, она обязательно использовала бы средства синхронизации и/или атомной операции, поэтому предоставленный пользователем weak_ptr::expired()
было бы в порядке, чтобы включить (реализация должна была гарантировать, что поток в конечном итоге достигнет прогресса, за [intro.multithread]/2 и /25). Но реализация не обязана ограничивать свою библиотеку языковыми и библиотечными средствами.
Я не совсем уверен, как компилятор оптимизирует доступ к expired()
. Я предполагаю, что библиотека MSVC использует аспекты модели памяти x86, которые наблюдатели компилятора/оптимизатора не гарантированы моделью памяти С++.