我有一个函数从一组字母表中生成随机字符。这个函数将被多次调用,因此我试图让它使用相同的变量集,即具有相同的种子,这样字符串就不会重复尽可能长的时间。
#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 <random>函数没有任何专门知识,而且我之前只使用了srand和朋友,所以我在这里可能会犯很多错误。目前,它不重复地工作并生成大量字符串,但我确信我可以做到以下两种:
std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<> dis(0, 61);静态变量也是如此,所以每次调用函数时都不会计算它,因为这会浪费时间,对吗?
那么哪一个应该是静态的呢?你在这里看到了什么错误/改进吗?
艾德龙
发布于 2018-10-26 20:18:03
无论您放在哪里,static都会极大地改变您的程序的行为。最后,我们有了2^3 = 8组合,所以让我们检查其中的一些。
如果没有用于随机数的硬件设备,random_device可能会退回到伪随机引擎。如果在本例中不对static使用random_device,则所有字符串都可能以相同的方式结束,因为伪随机引擎可能会使用定义的固定种子来初始化。
 std::random_device a;
 std::random_device b;
 assert(a() == b());  // worst case if no hardware-device or a low-effort implementation is used在这种情况下,mt19937将始终以相同的值作为种子,我们在每次调用中都会得到相同的字符串。如果mt19937或random_device是静态的,这种情况就会改变,如果dist是静态的,则可能会改变,因为uniform_int_distribution可以使用几次对生成器的内部状态调用。
当然,如果mt19937是静态的,那么您也可以将random_device更改为static变体,因为它只需要计算一次。这是您在程序开始时最接近单个srand()调用的地方。但是,您的uniform_int_distribution仍然失去了它的内部状态。
最后,这取决于我们是否希望两个generateRandomChar调用相互关联。如果它们根本不相关,我们需要用一个新的非确定数重新分配我们的PRNG,并且根本不能使用static。
或者,换一种说法:如果我们对所有三个值都使用static,那么
generateRandomChar(10) + generateRandomChar(10)与generateRandomChar(20)相同--如果我们在mt19937上使用static,那么两者可能是相同的,这取决于_len和dist。
无论哪种方式,如果您希望对生成有更多的控制,您只需在您的函数中提供一个生成器:
template <typename Generator>
std::string generateRandomChar(Generator & gen, const unsigned int _len)
    {
        ...
    }分配的情况也是一样。
除此之外,我将使用sizeof而不是61来确保在不更改dist's构造函数中的数字界的情况下,不会意外地更改可能的字符池:
static constexpr char alphanum[] = "0123456789"
                                   "abcdefghijklmnopqrstuvwxyz"
                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, sizeof(alphanum) - 1);发布于 2016-09-21 18:35:37
我认为您应该为此创建一个单独的包装类。我使用了以下方法:
#include <random>
class randomStreamUniformInt {
public:
    explicit randomStreamUniformInt(int lower_bound, int upper_bound)
    : mt(rand()), uniform_dist(lower_bound, upper_bound) {}
    explicit randomStreamUniformInt(int lower_bound, int upper_bound, double seed)
    : mt(seed), uniform_dist(lower_bound, upper_bound) {}
    int operator ()(void) { return uniform_dist(mt); }
private:
    std::mt19937_64                     mt;
    std::uniform_int_distribution<>     uniform_dist;
};显然,您可以将其扩展到使用首选生成器。然后,您应该将这个引用传递给您的函数,或者用generateRandomChar作为方法创建一个类。
https://codereview.stackexchange.com/questions/141989
复制相似问题