【问题标题】:Using t( *this ) results RuntimeError, while t( std::ref( *this ) does not使用 t( *this ) 会导致 RuntimeError,而 t( std::ref( *this ) 不会
【发布时间】:2016-01-16 11:17:30
【问题描述】:

我有以下例子:

#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 )

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

我不明白std::ref 在我做Obj() : t(std::ref(*this)) 时做了什么,以及为什么这会使程序工作。任何人都可以阐明发生了什么以及它是如何工作的吗?

【问题讨论】:

  • Obj() : t(*this) 工作正常。您的 Callback 是函子类型,您的 Obj 也是。
  • @Jean-BaptisteYunès 你是说编译器生成无效代码,因为Obj() : t(*this) 在运行时崩溃,但它应该可以正常工作?
  • 它适用于我的 g++ std c++11 编译器,我不明白为什么它不适合你。
  • 因为*this当时正在建设中,它的值可以无效是不是真的很奇怪...?
  • @binary01 你没有通过this,你通过了*this

标签: c++


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    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 的副本创建;这就是它不会崩溃的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-30
      • 2014-09-20
      • 2011-12-13
      • 2016-10-12
      • 2015-07-23
      • 1970-01-01
      • 2016-01-19
      • 1970-01-01
      相关资源
      最近更新 更多