在定义明确的 C++ 中,从引用中获取的指针是否可以为空?
Can pointer taken from reference ever be null in well-defined c++?
这个问题的动机是 clang 和 gcc 对 nullptr
检查指针值的不平衡处理。对于 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.";
}
}
尽管这个问题看起来很愚蠢,但我觉得它很实用。如果确实使用有臭味的代码,此优化会产生致命的结果,因此警告将是一种非常有用的诊断。
补充案例。 clang 和 gcc 都知道 check 有持续的评估,因为即使是干净的代码:
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
,在 g(A& a)
中省略了 if
,因此两者都能够确定并假设不可空性以供参考。 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()
中遗漏了 !
,修复了它。
Can pointer taken from reference ever be null in well-defined c++?
没有。此答案中的标准引号:Is null reference possible?
虽然,在使用 class 类型的重载 operator&
获取指针的特定情况下,可以 return 任何东西,包括 null。
Is it somehow possible for the if
to trigger?
不在 A::f
中,也不在 ::f
中。可以在 g(A*)
中触发,但在 g(A&)
.
中调用时则不能
a warning would be a really useful diagnostic.
GCC 和 Clang 都不够聪明,无法检测出您所观察到的这种情况下的错误,但它们确实检测到同一错误的更简单版本:
GCC
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
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) {
这个问题的动机是 clang 和 gcc 对 nullptr
检查指针值的不平衡处理。对于 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.";
}
}
尽管这个问题看起来很愚蠢,但我觉得它很实用。如果确实使用有臭味的代码,此优化会产生致命的结果,因此警告将是一种非常有用的诊断。
补充案例。 clang 和 gcc 都知道 check 有持续的评估,因为即使是干净的代码:
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
,在 g(A& a)
中省略了 if
,因此两者都能够确定并假设不可空性以供参考。 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()
中遗漏了 !
,修复了它。
Can pointer taken from reference ever be null in well-defined c++?
没有。此答案中的标准引号:Is null reference possible?
虽然,在使用 class 类型的重载 operator&
获取指针的特定情况下,可以 return 任何东西,包括 null。
Is it somehow possible for the
if
to trigger?
不在 A::f
中,也不在 ::f
中。可以在 g(A*)
中触发,但在 g(A&)
.
a warning would be a really useful diagnostic.
GCC 和 Clang 都不够聪明,无法检测出您所观察到的这种情况下的错误,但它们确实检测到同一错误的更简单版本:
GCC
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
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) {