C++ 使用std::enable_shared_时析构函数崩溃

C++ 使用std::enable_shared_时析构函数崩溃,c++,c++11,shared-ptr,C++,C++11,Shared Ptr,我正在尝试编写一个类似于类的boost信号(作为学习c++的练习)。我发现当我从这个中使用启用共享时,我总是在析构函数中崩溃。以下是代码(我正在使用vs2012更新2): 对此有何评论?此问题应该是由以下原因引起的:shared\u from\u This(),因为当我取消注释signal\u connection::disconnect中的行(auto This=shared\u from\u This();)时,一切正常 我知道它必须至少有一个有效的共享\u ptr,然后才能从\u this

我正在尝试编写一个类似于类的boost信号(作为学习c++的练习)。我发现当我从这个中使用
启用共享时,我总是在析构函数中崩溃。以下是代码(我正在使用vs2012更新2):

对此有何评论?此问题应该是由以下原因引起的:
shared\u from\u This()
,因为当我取消注释
signal\u connection::disconnect
中的行(
auto This=shared\u from\u This();
)时,一切正常

我知道它必须至少有一个有效的共享\u ptr,然后才能从\u this()
调用
shared\u。我的代码应该满足这一点

代码

    #include <memory>
    #include <map>

    class slot_manager;

    class signal_connection: public std::enable_shared_from_this<signal_connection>
    {
    public:
        signal_connection(slot_manager* manager)
            :manager_(manager)
        {}
    public:
        void disconnect() ;
    private:
        slot_manager* manager_;
    };

    class slot_manager
    {
    public:
        typedef std::shared_ptr<signal_connection> connection_type;
        typedef std::map<connection_type, int> map_type;
        typedef map_type::value_type map_value_type;
    public:
        void connect(int slot)
        {
            std::shared_ptr<signal_connection> c(new signal_connection(this));
            slots_.insert(map_value_type(c, slot));
        }
        ~slot_manager()
        {
            auto iter = slots_.begin();
            map_type::iterator iter2 = slots_.end();
            while (iter != slots_.end())
            {
                iter2 = iter++;
                iter2->first->disconnect();
            }
        }
        void disconnect(std::shared_ptr<signal_connection> connection)
        {
            auto c = slots_.find(connection);
            if (c != slots_.end())
            {
                slots_.erase(c);
            }
        }
    protected:
        map_type slots_;
    };

    void signal_connection::disconnect() 
    {
        if (manager_ != nullptr)
        {
            //auto this_ = shared_from_this();
            manager_->disconnect(shared_from_this());
            manager_ = nullptr;
        }
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        slot_manager x;
        x.connect(1);
    return 0;
    }
#包括
#包括
班级管理者;
类信号\u连接:公共std::从\u启用\u共享\u
{
公众:
信号连接(插槽管理器*管理器)
:经理(经理)
{}
公众:
无效断开连接();
私人:
插槽管理器*管理器;
};
类插槽管理器
{
公众:
typedef std::共享的ptr连接类型;
typedef std::map映射类型;
类型定义映射类型::值映射类型映射值类型;
公众:
无效连接(内部插槽)
{
std::共享ptr c(新信号连接(本));
插槽插入(映射值类型(c,插槽));
}
~slot_manager()
{
自动iter=slots_u.begin();
map_type::迭代器iter2=slots_u.end();
while(iter!=slots.end())
{
iter2=iter++;
iter2->first->disconnect();
}
}
无效断开连接(标准::共享ptr连接)
{
自动c=插槽查找(连接);
如果(c!=slots_u.end())
{
插槽擦除(c);
}
}
受保护的:
映射类型插槽;
};
无效信号_连接::断开连接()
{
if(管理器_!=nullptr)
{
//auto this_uu=从_this()共享_;
管理器->断开(共享的)与此()的连接;
经理=空PTR;
}
}
int _tmain(int argc,_TCHAR*argv[]
{
插槽管理器x;
x、 连接(1);
返回0;
}

问题在于,在将其管理器设置为
nullptr
之前,在
disconnect()
中断开信号连接,这会导致访问冲突,即通过调用管理器的disconnect。这是因为管理器持有连接的唯一
共享\u ptr
,而您
擦除()。该对象无法使自身保持活动状态。当然,除非您取消注释该行
的寿命足以避免此问题。

问题在于,在将其管理器设置为
nullptr
之前,信号连接在
disconnect()
中被断开,这会导致访问冲突,即通过调用管理器的disconnect。这是因为管理器持有连接的唯一
共享\u ptr
,而您
擦除()。该对象无法使自身保持活动状态。当然,除非您取消注释该行
这个
的寿命足够长,可以避免这个问题。

@KerrekSB:你是说,有礼貌的程序员从不在公共场合裸体?仅包装?:)当然,我更喜欢
共享
而不是
新建
,但这并不是这里出现问题的原因。值得一提的是,valgrind立即在Mac OS上发现了这个问题,即使程序没有崩溃。使用它,热爱它:valgrind。您可以简化代码,删除~slot_manager()析构函数,并为信号连接添加析构函数,该函数只调用disconnect()函数。地图将自动释放它的所有对象(调用它们的析构函数)。@CharlesBailey:Mm,没错。我将删除我的评论以避免混淆。@KerrekSB:你是说,有礼貌的程序员从不在公共场合裸体?仅包装?:)当然,我更喜欢
共享
而不是
新建
,但这并不是这里出现问题的原因。值得一提的是,valgrind立即在Mac OS上发现了这个问题,即使程序没有崩溃。使用它,热爱它:valgrind。您可以简化代码,删除~slot_manager()析构函数,并为信号连接添加析构函数,该函数只调用disconnect()函数。地图将自动释放它的所有对象(调用它们的析构函数)。@CharlesBailey:Mm,没错。我将删除我的评论以避免混淆。非常感谢。我的假设是,在析构函数'iter2->first->disconnect(),根据你的评论,这是错误的。再次感谢你!非常感谢你。我的假设是,在析构函数'iter2->first->disconnect(),根据你的评论,这是错误的。再次感谢你!