Быстрая случайная строка - PullRequest
0 голосов
/ 29 июня 2018

Я пытаюсь сгенерировать случайный идентификатор строки для программы (идентификатор должен быть уникальным только во время выполнения программы). Сначала я сделал это на Python без каких-либо проблем:

class RandomIdGenerator:
    _base_62_chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

    @classmethod
    def get_base_62(cls, length):
        return "".join([random.choice(RandomIdGenerator._base_62_chars) for _ in range(length)])

Но так как мне нужно, чтобы моя программа была на C ++, я пытаюсь сгенерировать с ней ту же строку. Вот что я делаю сейчас:

void Node::setId()
{
    QString allow_symbols("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
    qsrand(QTime::currentTime().msec());

    for (int i = 0; i < ID_LENGTH; ++i) {
        id_.append(allow_symbols.at(qrand() % (allow_symbols.length())));
    }
}

У меня есть две основные проблемы. Во-первых, он не использует C ++ 11 (я не знаю, как работает Qt, но я не думаю, что это C ++ 11), и сгенерированные идентификаторы одинаковы. Если я сгенерирую четыре из них, я получу:

"R4NDM1xM"
"R4NDM1xM"
"R4NDM1xM"
"R4NDM1xM"

Я пытался использовать метод C ++ 11, но получал один и тот же результат, даже хуже, при каждом выполнении я получал точно такой же результат:

void Node::setId()
{
    id_ = "";

    const std::string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    std::random_device rd;
    std::mt19937 generator(rd());
    std::uniform_int_distribution<int> dist(0, str.size() - 1);

    for (int i = 0; i < Node::ID_LENGTH; ++i)
        id_ += str[dist(generator)];
}

Как генерировать случайный идентификатор строки при каждом вызове метода?

1 Ответ

0 голосов
/ 29 июня 2018

Генераторы случайных чисел должны быть посеяны только один раз, если вам не нужно повторять последовательность случайных чисел снова. Это означает, что qsrand(QTime::currentTime().msec()); следует вызывать только при первом вводе setId(). Это немного сложно, так как это вызов функции, но вы можете добавить статическую переменную bool, чтобы отследить, была ли она запущена, а если нет, то не вызывать ее снова. Что-то вроде

void Node::setId()
{
    static bool seeded = false;
    QString allow_symbols("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
    if (!seeded) 
    {
        qsrand(QTime::currentTime().msec());
        seeded = true;
    }

    for (int i = 0; i < ID_LENGTH; ++i) {
        id_.append(allow_symbols.at(qrand() % (allow_symbols.length())));
    }
}

Код на C ++ 11 стал еще проще. Поскольку генератор случайных чисел является объектом, вы можете сделать его статическим, и он будет инициализирован только при первом вызове функции. Это означает, что ваш код становится:

void Node::setId()
{
    id_ = "";
    id_.reserve(Node::ID_LENGTH); // preallocate storage

    static const std::string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    static std::random_device rd;
    static std::mt19937 generator(rd());
    static std::uniform_int_distribution<int> dist(0, str.size() - 1);

    for (int i = 0; i < Node::ID_LENGTH; ++i)
        id_ += str[dist(generator)];
}

Следует также отметить, что std::random_device поддерживается недетерминированным источником. Если ваша реализация не поддерживает это, возможно, std::random_device будет выдавать одну и ту же последовательность каждый раз, когда вы ее вызываете. Если это так, то вам придется использовать другую опцию для заполнения generator, например, используя текущее время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...