c++ 为什么std :: weak_ptr :: expired已优化?

在下面的代码中,while(!Ref.expired());快乐地优化成一个无限循环。如果代码行更改为while(!Ref.lock());.一切正常工作。所以两个问题真的:

1)当std :: weak_ptr :: expired()访问内存防护计数器时,编译器如何优化远程过期?

2)Ref.lock()实际上是安全的,还是可以优化呢?

下面的示例代码。

#include <iostream>
#include <memory>
#include <thread>
#include <chrono>

class A
{
public:

    A() 
    { 
        m_SomePtr = std::make_shared<bool>( false );
    }

    virtual ~A()
    {
        std::weak_ptr<bool> Ref = m_SomePtr;
        m_SomePtr.reset();

        // Spin (will be optimised into an infinite loop in release builds)
        while ( !Ref.expired() );
    }

    std::shared_ptr<bool> GetPtr() const { return m_SomePtr; }

private:
    std::shared_ptr<bool> m_SomePtr;
};

class B
{
public:
    B( std::shared_ptr<bool> SomePtr ) : m_Ref( SomePtr ) {}

    void LockPtr() { m_SomePtr = m_Ref.lock(); }
    void UnLockPtr() { m_SomePtr.reset(); }

private:
    std::shared_ptr<bool> m_SomePtr;
    std::weak_ptr<bool> m_Ref;
};

int main()
{
    std::unique_ptr<A> a( new A() );
    std::unique_ptr<B> b( new B( a->GetPtr() ) );

    b->LockPtr();

    std::cout << "Starting " << std::endl;

    std::thread first( [&]()
    {
        std::this_thread::sleep_for( std::chrono::seconds( 5 ) );
        b->UnLockPtr();
    } );

    std::thread second( [&]()
    {
        a.reset( nullptr );
    } );

    first.join();
    second.join();

    std::cout << "Complete" << std::endl;
    return 0;
}
最佳答案
您的程序不正确;共享所有权指针设施不旨在用于同步。

[intro.multithread] / 24:

The implementation may assume that any thread will eventually do one of the following:
— terminate,
— make a call to a library I/O function,
— access or modify a volatile object, or
— perform a synchronization operation or an atomic operation.

std :: weak_ptr :: expired()不是同步操作或原子操作;所有的标准说,它不介绍数据竞赛。由于解析为Library defect 2316,std :: weak_ptr :: lock()被认为是一个原子操作,所以回答2)你的代码使用Ref.lock()从C 14开始有效。

现在,如果你试图使用语言和库设施来创建自己的weak_ptr库实现,那么它必然使用同步和/或原子操作设施,因此用户提供的weak_ptr :: expired()将会可以旋转(执行将不得不确保线程最终取得进展,每[intro.multithread] / 2和/ 25)。但实施并不强制将自己的图书馆限制在语言和图书馆设施。

我不完全确定编译器如何优化对expired()的访问。我想,MSVC库是利用x86内存模型的方面,编译器/优化器观察到的不是由C内存模型保证。

转载注明原文:c++ 为什么std :: weak_ptr :: expired已优化? - 代码日志