有趣的 C++ 代码片段,有啥解释吗? [复制]

Posted

技术标签:

【中文标题】有趣的 C++ 代码片段,有啥解释吗? [复制]【英文标题】:Interesting C++ code snippet, any explanations? [duplicate]有趣的 C++ 代码片段,有什么解释吗? [复制] 【发布时间】:2010-09-23 15:45:19 【问题描述】:

可能重复:Why am I able to make a function call using an invalid class pointer

class B

    public:
    int i;
    B():i(0)
    void func1()
    
        cout<<“func1::B\n”;
    
    void func2()
    
        cout<<“i = “<<i;
     
;


int main()


    B *bp = new B;

    bp->func1();

    delete bp;

    bp = NULL;

    bp->func1();
    bp->func2();

    return 1; 

输出:

func1::B 
func1::B 
Runtime Exception:
NULL pointer access

【问题讨论】:

代码无法编译:没有包含,main() 被错误声明。它确实 NOT 什么都不返回;它返回一个int 哇,它变成了社区维基。 显式取消引用 NULL ptr 有什么有趣的地方? int main 仍然是无效的方法声明/语法错误。 不,int main() 是标准的。编辑:我认为之前的评论是在抱怨之前的修订中缺少括号。 【参考方案1】:

这是NULL(或无效)对象指针的老故事;对于标准,在 NULL 对象指针上调用方法会导致未定义的行为,这意味着,就标准而言,它可以正常工作,它可能会炸毁计算机或杀死一些随机的人。

这里发生的事情是 C++ 编译器对类的典型实现的结果:类通常实际上是只包含字段的结构,所有方法实际上都是函数,它们将 this 指针作为隐藏参数。

现在,在这种实现中,如果您使用NULL this 指针调用方法,如果它不访问任何字段,它实际上不会取消引用this,所以它应该运行良好(就像func1 一样)。

相反,如果该方法尝试访问任何字段(例如func2),它将取消引用this 指针,该指针是NULL,将导致崩溃(取消引用NULL指针再次是未定义的行为,但通常会导致崩溃)。

请注意,如果您调用的方法是虚拟的,那么几乎可以肯定,使用 NULL this 指针调用它们会导致崩溃,因为虚拟调用是通过 vtable(函数指针数组),隐藏在类的开头。

顺便说一句,void main() 不是标准的;它应该是 int main()argvargc 是可选的)。

【讨论】:

谢谢,我发现您的解释对帮助我理解 sn-p 中的有趣内容非常有用。【参考方案2】:

当代码被修复编译时,结果是合理的。

func1() 没有引用该类的任何成员,因此它没有发现它有一个空指针作为this 使用; func2() 确实引用了 this-&gt;i,因此当 this 为空时失败。

严格来说,这是未定义的行为 - 任何事情都可能发生。但核心转储或运行时异常是对该特定错误的最常见响应之一。

【讨论】:

+1 确实。删除对象后,对其原始成员的任何访问都会导致意外行为,具体行为可能因您使用的编译器而异。【参考方案3】:

有什么好玩的?第一个输出是正确的。第二个未定义的行为。第三个是尝试访问包含在现在不存在的类中的信息。程序正确识别它是一个 NULL 指针。

【讨论】:

【参考方案4】:

不是专家意见,只是看看这个:

bp->func1() 不需要对类成员的任何访问 - 在 Java 中,这最好定义为静态。也许编译器正在内联函数?

【讨论】:

【参考方案5】:

您正在删除 bp 然后尝试从中调用,因为那里没有对象,实际上您已将引用设置为 null 存在运行时异常。

这样想:

您已经告诉编译器任何实例都不需要空间,因此当它尝试使用变量“i”时,它没有存储在任何有意义的地方并且程序失败。因为您已将引用设置为 null,所以程序会在执行此操作之前提前捕获它。

【讨论】:

【参考方案6】:

我认为严格来说,对 bp->func1() 的第二次调用应该已经崩溃,但是通过输出调用它仍然使用分配的 bp(但现在是 NULL),也许是一些错误的编译器优化(?)。然后在 bp->func1() 调用中它真的崩溃了,因为成员 i 不可访问。

【讨论】:

【参考方案7】:

从您在使用 delete 后使用指针的位置开始,您进入“未定义行为”区域

因此,超出这一点的任何行为都依赖于编译器实现,即使“看起来可行”也必须被视为错误。

【讨论】:

以上是关于有趣的 C++ 代码片段,有啥解释吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C++ 这个类和单例的全局声明有啥好的选择吗? [复制]

这些 C++ 代码片段有啥作用?

在 C++ 11 中初始化二维数组有啥好的方法吗? [复制]

有人可以为我解释一下 C++ 代码吗? [复制]

C# 到 C++ 多线程,有啥问题吗?

字符串插值和片段之间有啥显着区别吗?