luk*_*k32 4 c++ pointers reference null-pointer language-lawyer
这个问题是由于检查指针值nullptr受到clang和gcc 的不均衡处理而引起的。因为this它们都发出警告,但是对于address-of在对象上使用运算符获取的指针,它们保持安静。
我很确定这样的指针应该一直有效,因为现代编译器从快乐的90年代实际上取消了对c ++代码的检查,导致了我们遇到的错误。
令我感到困惑的是,为什么编译器在一般情况下保持安静。是否可以通过某种方式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.";
}
}
Run Code Online (Sandbox Code Playgroud)
尽管这个问题看起来很愚蠢,但我发现它很实用。如果使用臭代码工作,则此优化将导致致命的结果,因此警告将是非常有用的诊断。
以补充情况。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);
}
Run Code Online (Sandbox Code Playgroud)
它们产生的两个版本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
Run Code Online (Sandbox Code Playgroud)
据我了解组装,msvc /O2并icc -fast保留检查到位。
编辑:我错过!了A::f(),修复它。
Can pointer taken from reference ever be null in well-defined c++?
No. Standard quotes in this answer: Is null reference possible?
Although, in particular case of taking the pointer using an overloaded operator& of a class type can return anything, including null.
Is it somehow possible for the
ifto trigger?
Not in A::f nor ::f. It is possible to trigger in g(A*) but not when called from g(A&).
a warning would be a really useful diagnostic.
GCC nor Clang are not smart enough to detect the mistake in that case as you've observed, but they do detect a simpler version of the same mistake:
GCC
Run Code Online (Sandbox Code Playgroud)warning: the compiler can assume that the address of 'a' will never be NULL [-Waddress] if(&a == nullptr) { ~~~^~~~~~~~~~ warning: nonnull argument 'a' compared to NULL [-Wnonnull-compare] if(&a == nullptr) { ^~Clang
Run Code Online (Sandbox Code Playgroud)warning: reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to false [-Wtautological-undefined-compare] if(&a == nullptr) {
| 归档时间: |
|
| 查看次数: |
130 次 |
| 最近记录: |