使用 t( *this ) 会导致运行时错误,而 t( std::ref( *this ) 则不会

Using t( *this ) results RuntimeError, while t( std::ref( *this ) does not

本文关键字:this ref std 使用 运行时错误      更新时间:2023-10-16

我有以下示例:

#include <iostream>
#include <functional>
struct Tmr {
    typedef std::function<void(void)> Callback;
    Callback cb;
    Tmr(Callback cb_) :
        cb( cb_ )
    {
    }
    void timeout()
    {
        cb();
    }
};
struct Obj {
    struct Tmr t;
    Obj() :
        t( std::ref( *this ) )
    {
    }
    void operator () ()
    {
        std::cout << __func__ << 'n';
    }
};
int main(int argc, char *argv[])
{
    Obj o;
    o.t.timeout();
    return 0;
}

这运行良好,但最初我将Obj的构造函数设置为:

Obj() :
    t( *this )

这会导致运行时错误。我想这是因为我的回调中只存储了对成员函数的引用,而不是调用成员的对象。

我不明白的是,当我做Obj() : t(std::ref(*this))时,std::ref做了什么,以及为什么这会让程序工作。任何人都可以阐明正在发生的事情及其工作原理吗?

当你不通过引用传递时,你会在初始化t之前复制*this - 这意味着你在初始化之前复制t及其回调成员,这是未定义的行为。

std::function 的复制构造函数可能会尝试复制未初始化指针指向的内容,这就是导致实际崩溃的原因。

由于复制未初始化的回调对象,您的代码崩溃。您可以在下面看到一系列事件:

1. Copy constructor of Obj is called in t(*this)
2. Copy constructor of Tmr is called as t is a member of Obj
3. Copy constructor of Callback is called as cb is a member of Tmr
4. Execution fails while trying to copy from uninitialized Callback object.

通过使用 std::ref,您可以绕过 Obj 的副本创建;这就是它不会崩溃的原因。