I was watching a video of Alexandrescu's, he has the following code snippet:
// an example implementation of a single threaded shared_ptr
~SingleThreadPtr() {
if(!c_) {
soSueMe: delete p_;
} else if(--*c_ == 0) {
delete c_;
goto soSueMe;
}
}
This is here https://youtu.be/Qq_WaiwzOtI?t=36m44s. He says, "I use my famous 'goto soSueMe' construct", and says "try to write this without goto and [..] you'll see it is difficult".
What is so difficult here? Isn't the following the same, and obviously not difficult, and more readible:
// an example implementation of a single threaded shared_ptr
~SingleThreadPtr() {
if(!c_) {
delete p_;
} else if(--*c_ == 0) {
delete c_;
delete p_;
}
}
or is that not even the same (thereby reinforcing the arguments against goto
in the first place)? What sort of hacker's black magic voodoo going on here?
The point here is that shared_ptr destructors are called relatively often, and generally inline, and this is an attempt to reduce the inlined destructor size (as a goto
is much smaller than a delete call).
For example, the destructor call delete p_
when compiled may look something like:
LBB5_8:
movq -16(%rbp), %rax ## 8-byte Reload
movq (%rax), %rcx
cmpq $0, %rcx
movq %rcx, -24(%rbp) ## 8-byte Spill
je LBB5_4
movq -24(%rbp), %rax ## 8-byte Reload
movq %rax, %rdi
callq __ZdlPv
LBB5_4:
(where the callq __ZdlPv
is the underlying object destructor finally being called).
Whereas the goto
looks simply like this:
LBB5_8:
jmp LBB5_2
Thus, by branching rather than repeating the delete p_
statement, codesize is significantly reduced.
This accompanying presentation may prove useful reading (although terse).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With