Consider a simple program:
int main() {
int* ptr = nullptr;
delete ptr;
}
With GCC (7.2), there is a call
instruction regarding to operator delete
in the resulting program. With Clang and Intel compilers, there are no such instructions, the null pointer deletion is completely optimized out (-O2
in all cases). You can test here: https://godbolt.org/g/JmdoJi.
I wonder whether such an optimization can be somehow turned on with GCC? (My broader motivation stems from a problem of custom swap
vs std::swap
for movable types, where deletion of null pointers can represent a performance penalty in the second case; see https://mcmap.net/q/88980/-move-semantics-custom-swap-function-obsolete for details.)
UPDATE
To clarify my motivation for the question: If I use just delete ptr;
without if (ptr)
guard in a move assignment operator and a destructor of some class, then std::swap
with objects of that class yields 3 call
instructions with GCC. This might be a considerable performance penalty, e.g., when sorting an array of such objects.
Moreover, I can write if (ptr) delete ptr;
everywhere, but wonder, whether this cannot be a performance penalty as well, since delete
expression needs to check ptr
as well. But, here, I guess, compilers will generate a single check only.
Also, I really like the possibility to call delete
without the guard and it was a surprise for me, that it could yield different (performance) outcomes.
UPDATE
I just did a simple benchmark, namely sorting objects, which invoke delete
in their move assignment operator and destructor. The source is here: https://godbolt.org/g/7zGUvo
Running times of std::sort
measured with GCC 7.1 and -O2
flag on Xeon E2680v3:
There is a bug in the linked code, it compares pointers, not pointed values. Corrected results are as follows:
- without
if
guard:17.6 [s]40.8 [s], - with
if
guard:10.6 [s]31.5 [s], - with
if
guard and customswap
:10.4 [s]31.3 [s].
These results were absolutely consistent across many runs with minimal deviation. The performance difference between first two cases is significant and I wouldn't say that this is some "exceedingly rare corner case" like code.
if
beforedelete
? – Placeedaoperator delete
? – Handicraftptr
to beconstexpr
, and see if gcc does the optimization then. – Placeedaswap
vsstd::swap
case, when useif
both in destructor and move assignment operator. I just liked the possibility not to write such a guard. – Melonieswap
vsstd::swap
? – Melonie