在构造函数中初始化<random>类会导致segfault

时间:2015-06-05 16:13:07

标签: c++ c++11 random

在下面的代码中,RandomCharSource应该只是在请求时返回一个随机字符。它的构造函数正在初始化mt19937uniform_int_distribution<int>random_device。但是,当我实例化我的对象时,我会遇到一个段错误。

当我在下面的bar()函数中手动创建这些随机类时,它可以正常工作。

我做错了什么?这里有初始化订单问题吗?我正在使用GCC 4.7.3。

#include <random>
#include <iostream>

class RandomCharSource
{
public:
    explicit RandomCharSource() : _re{_rd()}, _dist{0, 255} {};
    inline char get_next_char() { return _dist(_re); };
private:
    std::mt19937 _re;
    std::uniform_int_distribution<int> _dist;
    std::random_device _rd;
};

void foo()
{
    RandomCharSource s;
    std::cout << s.get_next_char() << std::endl;
}

void bar()
{
    std::random_device _rd;
    std::mt19937 _re{_rd()};
    std::uniform_int_distribution<int> _dist{0,255};
    std::cout << (char)_dist(_re) << std::endl;
}

int main()
{
    bar(); // Works OK
    foo(); // Segfault

    return 0;
}

1 个答案:

答案 0 :(得分:5)

这是因为您的初始化顺序

class RandomCharSource
{
public:
    explicit RandomCharSource() : _re{_rd()}, _dist{0, 255} {};
    inline char get_next_char() { return _dist(_re); };
private:
    std::mt19937 _re;
    std::uniform_int_distribution<int> _dist;
    std::random_device _rd;
};

您需要在_rd之前_re。成员按照在类中声明的顺序进行初始化。因此,当您尝试使用_re初始化_rd时,_rd尚未初始化。

来自标准§12.6.2.13(强调我的)

  

在非委托构造函数中,初始化按以下顺序进行:

     

13.1 - 首先,仅对于派生程度最高的类(1.8)的构造函数,虚拟基类按照它们出现在基类有向无环图的深度优先从左到右遍历的顺序进行初始化,其中“从左到右”是派生类base-specifier-list中基类出现的顺序。
  13.2 - 然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中(无论mem-initializers的顺序如何)。
  13.3 - 然后,非静态数据成员按照在类定义中声明的顺序进行初始化(同样不管mem-initializers的顺序如何)。
  13.4 - 最后,执行构造函数体的复合语句   [注意:声明命令的目的是确保基础和成员子对象在销毁中被销毁   初始化的逆序。 - 后注]