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

Initializing <random> classes in constructor causes segfault

本文关键字:段错误 错误 初始化 random lt gt 构造函数      更新时间:2023-10-16

在下面的代码中,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;
}

这是因为你的初始化顺序

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;
};

你需要在_re之前有_rd。成员按照在类中声明的顺序初始化。所以当你尝试用_rd初始化_re时,_rd还没有初始化。

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

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

13.1 -首先,并且仅对于最派生类的构造函数(1.8),虚基类按照它们在基类的有向无环图的深度优先的从左到右遍历中出现的顺序进行初始化,其中"从左到右"是基类在派生类基指定符列表中出现的顺序。
13.2 -然后,直接基类按照它们出现在基类说明符列表中的声明顺序进行初始化(与初始化器的顺序无关)。
13.3 -然后,非静态数据成员按照它们在类定义中声明的顺序初始化(同样与mems初始化器的顺序无关)。
13.4 -最后执行构造函数体的复合语句。
[注:声明顺序是强制的,以确保基和成员子对象在初始化的反向顺序。端注)