You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

(const)类对象销毁期间的成员访问是否存在未定义行为?

C++程序未定义行为分析

核心问题

取消注释下述代码中的任意一行注释后,程序是否存在未定义行为(UB)?

#include<atomic>
#include<iostream>
#include<thread>

std::atomic<bool> a = false;

struct T {
    int i;
    void reset() { i = 0; }
    ~T() {
        while(!a);
        //reset();
        a = false;
        while(!a);
    }
};

int main() {
    std::thread x;
    {
        const T t{42};
        x = std::thread([&t]{
            std::cout << t.i << "\n";
            a = true;
            while(a);
            //const_cast<T&>(t).reset();
            //const_cast<int&>(t.i) = 0;
            std::cout << t.i << "\n";
            a = true;
        });
    }
    x.join();
}

编译器行为差异

GCC运行后输出42后接0,而Clang两次输出42。

场景分析

原线程捕获t引用的情况

直觉判断这属于未定义行为:t的生存期在析构函数调用时结束,线程中对t.i的访问跨越了对象生存期。不过t此时处于“销毁中”的特殊阶段,目前尚未找到C++标准中明确判定此情况为UB的条款。

修改为捕获t.i引用的场景

如果不在线程中直接使用t,而是在析构函数调用开始前同步捕获t.i的引用,后续通过该引用进行读写操作——这种情况下无需在对象生存期外访问t的成员。有意思的是,这种写法下Clang不会再出现两次输出42的情况。

const限定符的影响

t的const限定符本身不决定是否构成UB,但会影响编译器的优化逻辑,比如Clang的处理方式。除了对象构造和销毁期间,自动存储期的const对象不可被修改或替换,因此编译器通常会假设i的值不会发生变化,哪怕t的引用逃逸到了未知函数中。

内容的提问来源于stack exchange,提问作者user17732522

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 13:02:37