首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >生成随机字符字符串

生成随机字符字符串
EN

Code Review用户
提问于 2016-09-21 04:59:25
回答 2查看 671关注 0票数 5

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

代码语言:javascript
运行
复制
#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);

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

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

艾德龙

EN

回答 2

Code Review用户

发布于 2018-10-26 20:18:03

无论您放在哪里,static都会极大地改变您的程序的行为。最后,我们有了2^3 = 8组合,所以让我们检查其中的一些。

如果没有用于随机数的硬件设备,random_device可能会退回到伪随机引擎。如果在本例中不对static使用random_device,则所有字符串都可能以相同的方式结束,因为伪随机引擎可能会使用定义的固定种子来初始化。

代码语言:javascript
运行
复制
 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将始终以相同的值作为种子,我们在每次调用中都会得到相同的字符串。如果mt19937random_device是静态的,这种情况就会改变,如果dist是静态的,则可能会改变,因为uniform_int_distribution可以使用几次对生成器的内部状态调用。

当然,如果mt19937是静态的,那么您也可以将random_device更改为static变体,因为它只需要计算一次。这是您在程序开始时最接近单个srand()调用的地方。但是,您的uniform_int_distribution仍然失去了它的内部状态。

最后,这取决于我们是否希望两个generateRandomChar调用相互关联。如果它们根本不相关,我们需要用一个新的非确定数重新分配我们的PRNG,并且根本不能使用static

或者,换一种说法:如果我们对所有三个值都使用static,那么

代码语言:javascript
运行
复制
generateRandomChar(10) + generateRandomChar(10)

与generateRandomChar(20)相同--如果我们在mt19937上使用static,那么两者可能是相同的,这取决于_lendist

无论哪种方式,如果您希望对生成有更多的控制,您只需在您的函数中提供一个生成器:

代码语言:javascript
运行
复制
template <typename Generator>
std::string generateRandomChar(Generator & gen, const unsigned int _len)
    {
        ...
    }

分配的情况也是一样。

除此之外,我将使用sizeof而不是61来确保在不更改dist's构造函数中的数字界的情况下,不会意外地更改可能的字符池:

代码语言:javascript
运行
复制
static constexpr char alphanum[] = "0123456789"
                                   "abcdefghijklmnopqrstuvwxyz"
                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, sizeof(alphanum) - 1);
票数 2
EN

Code Review用户

发布于 2016-09-21 18:35:37

我认为您应该为此创建一个单独的包装类。我使用了以下方法:

代码语言:javascript
运行
复制
#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作为方法创建一个类。

票数 -1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/141989

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档