I need to generate large number of UUIDs. If I don't make rg static, it would take lot of time in default constructing it every time. Is there anything wrong if I make it static, would it hurt uniqueness of uuids in anyway?
No, that's fine...
Is there any better way to do it?
... maybe, depending on the number of iterations you're going to need.
You see the (minor) trouble with static objects at function scope is in the wording of the standard, which dictates that:
a) The object is constructed the first time code flows over the statement and
b) That this construction must be thread-safe.
In practice this means that the code in generateUUID()
must test whether it has already constructed the object. This involves a memory fetch and a conditional branch.
Here is the assembler code output from your function when compiled on apple clang 7.0 with -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
This is necessary because anyone could call the function. The optimiser can't know whether the construction has happened before or not. So we're stuck with 3 extra instructions we don't really want because we chose the luxury of having our object constructed when needed.
And this means that if you're in a tight loop you may want to avoid all these redundant tests.
The question is, what is the cost of creating a generator vs the cost of a 3 million instruction executions and a (hopefully) correctly predicted branch?
At some large number of iterations, the following code actually becomes more efficient (if that really matters to you):
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
}
}
with the most efficient use of a static generator being this:
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
}
}
However this is slightly less convenient since we must now take care that nothing uses rg
until main()
has been called (unless you only use it in the same compilation unit in which it was defined).