Есть ли какие-либо проблемы с тем, чтобы сделать random_generator статическим?

Мне нужно сгенерировать большое количество UUID. Если я не сделаю rg static, это займет много времени при построении по умолчанию каждый раз. Что-то не так, если я сделаю это статичным, не повредит ли это уникальности uuids?

Есть ли лучший способ сделать это?

using namespace boost::uuids;

uuid generateUUID() {
static random_generator rg; // here
return rg();
}

void someFunction() {
for (int i = 0; i < 1000000; ++i) {
uuid id = generateUUID();
// use id
}
}

2

Решение

Нет, с этим проблем нет.

0

Другие решения

Мне нужно сгенерировать большое количество UUID. Если я не сделаю rg статическим, то при его создании по умолчанию потребуется много времени. Что-то не так, если я сделаю это статичным, не повредит ли это уникальности uuids?

Нет, все в порядке …

Есть ли лучший способ сделать это?

… возможно, в зависимости от количества итераций, которые вам понадобятся.

Вы видите (незначительную) проблему со статическими объектами в области видимости функции в формулировке стандарта, которая требует, чтобы:

а) Объект построен первый раз код течет по заявлению и

б) что эта конструкция должна быть поточно-ориентированной.

На практике это означает, что код в generateUUID() должен проверить, построил ли он уже объект. Это включает выборку памяти и условную ветвь.

Вот код ассемблера, выводимый из вашей функции при компиляции на apple clang 7.0 с -O3:

__Z12generateUUIDv:                     ## @_Z12generateUUIDv
Lfunc_begin0:
.cfi_startproc
.cfi_personality 155, ___gxx_personality_v0
.cfi_lsda 16, Lexception0
## BB#0:
pushq   %rbp
Ltmp3:
.cfi_def_cfa_offset 16
Ltmp4:
.cfi_offset %rbp, -16
movq    %rsp, %rbp
Ltmp5:
.cfi_def_cfa_register %rbp
pushq   %rbx
subq    $24, %rsp
Ltmp6:
.cfi_offset %rbx, -24
movb    __ZGVZ12generateUUIDvE2rg(%rip), %al  ## MEMORY FETCH
testb   %al, %al                              ## TEST
jne LBB0_4                                    ## CONDITIONAL BRANCH
## BB#1:
leaq    __ZGVZ12generateUUIDvE2rg(%rip), %rdi ## another check in case
callq   ___cxa_guard_acquire                  ## 2+ threads are racing
testl   %eax, %eax
je  LBB0_4
...                                               ## object constructed here

Это необходимо, потому что любой может вызвать функцию. Оптимизатор не может знать, произошло ли строительство раньше или нет. Таким образом, мы застряли с 3 дополнительными инструкциями, которые нам на самом деле не нужны, потому что мы выбрали роскошь строительства нашего объекта при необходимости.

А это значит, что если вы в тесной петле может хочу избежать всех этих лишних тестов.

Вопрос в том, какова стоимость создания генератора по сравнению со стоимостью 3 миллионов выполнений команд и (надеюсь) правильно предсказанной ветви?

При большом количестве итераций следующий код фактически становится более эффективным (если это действительно важно для вас):

void someFunction() {
// one generator used for the duration of the function
random_generator rg;
for (int i = 0; i < 1000000; ++i) {
uuid id = rg();
// use id
}
}

с наиболее эффективным использованием статического генератора:

using namespace boost::uuids;

static random_generator rg; // constructed at some point before main() is called
// we no longer require flag tests

void someFunction() {
for (int i = 0; i < 1000000; ++i) {
uuid id = rg();
// use id
}
}

Однако это немного менее удобно, так как теперь мы должны позаботиться о том, чтобы ничего не использовалось rg до тех пор main() был вызван (если только вы не используете его в том же модуле компиляции, в котором он был определен).

0