Этот вопрос мотивирован неравномерной обработкой проверки значения указателя по nullptr
clang и gcc. Для this
они оба выдают предупреждение, но для указателя, взятого с помощью оператора address-of
на объект, они хранят молчание.
Я почти уверен, что такой указатель всегда должен быть действительным, потому что мы столкнулись с ошибками из-за того, что современный компилятор удалил такие проверки кода c ++ из счастливых 90-х годов, когда он действительно срабатывал.
Меня беспокоит, почему компиляторы молчат в общем случае. Возможно ли как-то запустить if
или это просто проектное решение в обоих основных компиляторах? Прежде чем я начну писать патчи или глючить для разработчиков компиляторов, я хотел бы убедиться, что не пропуская что-то.
Пример игрушки :
#include <iostream>
class A {
void f(){
if(!this) {
std::cout << "This can't trigger, and compilers warn about it.";
}
}
};
void f(A& a){
A* ptr = &a;
if(ptr == nullptr) {
std::cout << "Can this trigger? Because gcc and clang are silent.";
}
}
Хотя вопрос кажется довольно тупым, я считаю его практичным. Если кто-то работает с вонючим кодом, эта оптимизация приводит к фатальным результатам, поэтому предупреждение будет действительно полезной диагностикой.
В дополнение к делу. И clang, и gcc знают, что проверка имеет постоянную оценку, потому что даже для чистого кода:
void g(A* a){
A* ptr = a;
if(ptr == nullptr) {
std::cout << "Gee, can this trigger? Be cause gcc and clang are silent.";
}
}
void g(A& a) {
g(&a);
}
Они генерируют две версии g
с if
, опущенным в g(A& a)
, поэтому обе могут определить и принять ненулевое значение для справки. gcc создает хорошую читаемую сборку:
f(A&):
ret
.LC0:
.string "Can this trigger? Be cause gcc and clang are silent."
g(A*):
test rdi, rdi
je .L5
ret
.L5:
mov edx, 52
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:_ZSt4cout
jmp std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
g(A&):
ret
Насколько я понимаю сборка msvc /O2
и icc -fast
оставить чек на месте.
РЕДАКТИРОВАТЬ: я пропустил !
в A::f()
, исправил.