使用静态

时间:2016-09-21 04:42:43

标签: c++ linux c++11 random

我有一个从一组字母表中生成随机字符的功能。这个函数会被多次调用,因此我试图让它使用相同的变量集,即具有相同的种子,以便字符串不会尽可能长地重复。

#include <iostream>
#include <random>
#include <string>

std::string generateRandomChar(const unsigned int _len)
    {
        std::string result;
        result.reserve(_len);

        static constexpr char alphanum[] = "0123456789"
                                           "abcdefghijklmnopqrstuvwxyz"
                                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<> dis(0, 61);

        for (int i = 0; i < _len; 
            result += (alphanum[dis(gen)]);
        }
        return result;
    }

int main(){
    for(int i = 0; i < 10; ++i){
        std::cout << generateRandomChar(10) << std::endl;
    }
}

不幸的是我对c ++ 11函数没有任何专业知识,我之前只使用srand和朋友,所以我可能在这里犯了很多错误。目前它工作并生成大量的字符串而不重复,但我相信我可以制作 -

  • std::random_device rd;
  • std::mt19937 gen(rd());
  • std::uniform_int_distribution<> dis(0, 61);

也是静态变量,因此每次调用函数时都不会计算它,因为这样会浪费吗?

那么哪一个应该是静态的呢?你在这里看到任何错误/改进吗?

谢谢你:D

编辑 - 这是一个ideone链接 - http://ideone.com/e7ssXo

3 个答案:

答案 0 :(得分:2)

  

那么哪一个应该是静态的?

std::mt19937 gen或其中没有一个。

std::random_device使用非确定性熵源生成均匀分布的随机整数(如果可用)。您的代码使用std::random_device输出作为std::mt19937伪随机生成器的种子。因此,如果你在PC上运行,你很可能会为std::mt19937提供良好的,非确定性的种子,因此不需要将它们中的任何一个静态化。我认为std::random_device仅在低端控制器上实现为纯程序PRNG。

另一方面,一次性播种更具惯用性,因此您可以将std::mt19937声明为静态。 std::mt19937本身实现了具有19937位状态的高质量PRNG算法,因此如果生成器在现代PC上运行,它的周期可能超过Universe生命周期(或至少stelliferous era)。 / p>

不需要使std::uniform_int_distribution静态,因为它只是一个根据所需分布属性修改实际生成器输出的包装器。因此,您可以自行决定是否将其设为静态。

答案 1 :(得分:1)

您可以将random_devicemt19937设为静态。目前你每次调用函数时都会构建一个函数(IIRC,mt19937构造成本很高。有人核心我)。此外,您的uniform_int_distribution可以移出循环。这个问题更适合代码审查,因为它已经有效并且您正在寻求改进。

TL; DR:你可以使它们全部静止。

答案 2 :(得分:1)

为了允许单元测试,我建议将发生器移出函数之外,如

std::string generateRandomChar(const unsigned int len, std::mt19937& gen)
{
    std::string result;
    result.reserve(len);

    static constexpr char alphanum[] = "0123456789"
                                       "abcdefghijklmnopqrstuvwxyz"
                                       "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    std::uniform_int_distribution<> dis(0, 61);

    for (int i = 0; i < len; ++i) {
        result += (alphanum[dis(gen)]);
    }
    return result;
}

int main() {
    std::random_device rd;
    std::mt19937 gen(rd());

    for (int i = 0; i < 10; ++i) {
        std::cout << generateRandomChar(10, gen) << std::endl;
    }
}

或创建一个类

class RandomCharGenerator
{
public:
    RandomCharGenerator() : RandomCharGenerator(std::random_device{}()) {}

    template <typename T>
    RandomCharGenerator(T&& seed) : gen(std::forward<T>(seed)) {}

    std::string operator() (const unsigned int len)
    {
        std::string result;
        result.reserve(len);

        for (int i = 0; i < len; ++i) {
            result += (alphanum[dis(gen)]);
        }
        return result;
    }

private:
    std::mt19937 gen;
    std::uniform_int_distribution<> dis{0, 61};
    static constexpr char alphanum[] = "0123456789"
                                       "abcdefghijklmnopqrstuvwxyz"
                                       "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
};

int main() {
    RandomCharGenerator charGenerator{};

    for (int i = 0; i < 10; ++i) {
        std::cout << charGenerator(10) << std::endl;
    }
}

你最终可以模仿事物以允许其他兰特生成器。