c++ - 在定义明确的 C++ 中,从引用中获取的指针是否可以为空?

标签 c++ pointers reference language-lawyer null-pointer

这个问题的动机是 clang 和 gcc 对检查指针值与 nullptr 的不平衡处理。对于 this,它们都发出警告,但对于通过在对象上使用 address-of 运算符获取的指针,它们保持安静。

我很确定这样的指针应该始终有效,因为我们遇到过错误,因为现代编译器从快乐的 90 年代实际触发的地方删除了对 c++ 代码的此类检查。

令我困惑的是为什么编译器在一般情况下保持安静。 if 是否有可能以某种方式触发,或者这只是两个主要编译器的设计决定?在我开始编写补丁或窃听编译器开发人员之前,我想以确保我没有遗漏任何东西。

Toy example :

#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/O2icc -fast 保留检查。

编辑:我在 A::f() 中遗漏了 !,修复了它。

最佳答案

Can pointer taken from reference ever be null in well-defined c++?

没有。此答案中的标准引号:Is null reference possible?

虽然,在使用类类型的重载 operator& 获取指针的特殊情况下,可以返回任何内容,包括 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) {

关于c++ - 在定义明确的 C++ 中,从引用中获取的指针是否可以为空?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56756766/

相关文章:

c++ - 事件发射器和成员方法自动注册为监听器

c++ - 程序员的错误或 gcc-5.1.0 的错误?

c - 子进程死亡后,子进程中声明的所有指针都会被释放吗?

c# - 引用 C# 中的引用

java - 如何验证/强制类被垃圾收集

python - std::reference_wrapper 是否类似于 python 的传递对象引用?

c++ - 如何暂停进程中的所有线程(停止世界)

c++ - C++ 中的大指数

c++ - 如何使用虚表正确调用成员方法?

c - 为什么这段代码会产生输出 513?