在结构中使用随机库后删除函数错误

zar*_*rro 1 c++ random struct std deleted-functions

我正在尝试围绕标准随机数生成器编写一个简单的结构。根据编译器,我可以初始化此类,但是当我尝试使用该函数时,它会出现以下错误:

错误 C2280 'RandNormGen::RandNormGen(const RandNormGen &)':尝试引用已删除的函数

我不完全理解这意味着什么或该怎么做,但我认为我将其范围缩小到与 std ::random_device rd;有关。

这是我的结构:

struct RandNormGen {
    std::random_device rd;
    std::mt19937 gen;
    std::normal_distribution<float> normalDist;

    RandNormGen() {
        gen = std::mt19937(rd());
        normalDist = std::normal_distribution<float>(0, 1);
    }

    float randFloat(float sigma, float mean = 0) {
        float r = normalDist(gen) * sigma + mean;
        return r;
    }
};
Run Code Online (Sandbox Code Playgroud)

任何帮助或见解将不胜感激!

use*_*522 6

std::random_device不可复制或移动。所以你的类也不能被复制或移动。

然而,保留该实例实际上没有任何意义std::random_device。您(希望)仅使用它来为实际的随机数生成器提供种子。因此,将其从结构体中删除,改为在构造函数中:

gen = std::mt19937(std::random_device{}());
Run Code Online (Sandbox Code Playgroud)

或者完全跳过构造函数并使用默认成员初始值设定项,因为默认构造函数除了初始化成员之外什么也不做:

struct RandNormGen {
    std::mt19937 gen{std::random_device{}()};
    std::normal_distribution<float> normalDist;

    float randFloat(float sigma, float mean = 0) {
        float r = normalDist(gen) * sigma + mean;
        return r;
    }
};
Run Code Online (Sandbox Code Playgroud)

( 的默认构造函数std::normal_distribution已经初始化为分布参数 和 ,01std::normal_distribution<float> normalDist{0, 1};可以工作。)


但是,请注意您所做的事情首先会导致需要复制构造函数。

如果您实际上复制而不是移动类对象,则最终会得到该类的两个实例,它们具有相同的随机数生成器状态,这意味着副本中生成的随机数不会与原始中生成的随机数不同。

如果这不是您想要的行为,您可以显式删除复制构造函数,以便只允许移动:

RandNormGen() = default;

RandNormGen(const RandNormGen&) = delete;
RandNormGen(RandNormGen&&) = default;

RandNormGen& operator=(const RandNormGen&) = delete;
RandNormGen& operator=(RandNormGen&&) = default;
Run Code Online (Sandbox Code Playgroud)

或者您可以使用预期的语义定义复制构造函数和赋值运算符(例如重新播种生成器)。


更一般地说,考虑将随机数生成器移出类。为每个对象配备一个随机生成器通常没有任何意义。通常,程序中的每个线程都有一个生成器就足够了。