为什么即使在对象被销毁后成员变量仍可修改?

Why are member variables modifyable even after object is destroyed?

如果 shared_ptr 被销毁,如果在 lambda 中捕获到线程上的 运行,“this”会发生什么?它不应该在下面的情况下抛出异常,因为对象 Test 在线程完成之前被销毁 运行ning.

#include <iostream>
#include <thread>
#include <chrono>

using namespace std;
using namespace std::this_thread; // sleep_for, sleep_until
using namespace std::chrono; // nanoseconds, system_clock, seconds


class Test 
{
    private:
    int testInt = 0;
    
    public:
    std::thread TestMethod()
    {
        auto functor = 
        [this]() ->void 
        {
            sleep_until(system_clock::now() + seconds(1));
            ++testInt; cout<<testInt<<endl;
        };
        
        std::thread t1(functor);
        testInt = 6;
        return t1;
    }
    
    ~Test()
    {
        cout<<"Destroyed\n";
        testInt = 2;
    }
};

int main()
{
    cout<<"Create Test\n";
    auto testPtr = std::make_shared<Test>();
    auto t = testPtr->TestMethod();
    testPtr = nullptr;
    cout<<"Destroy Test\n";
    t.join();

    return 0;
}

输出为

Create Test
Destroyed
Destroy Test
3

lambda 如何访问已销毁对象的 testInt?

实际上,执行程序的硬件对对象、成员变量、引用或指针一无所知。 C++ 源代码中的变量成为可执行文件中的虚拟内存位置,而引用或指针成为虚拟内存地址。当一个对象被你的程序“销毁”时,这对机器来说毫无意义。该程序只是停止为此目的使用那部分虚拟内存,如果程序继续 运行,它很可能会在不久之后重新分配该内存用于其他目的。

如果您的程序将 dangling reference/pointer 保存到之前被“销毁”的对象,那么通过该 pointer/reference 进行的任何访问都将是对现在未使用的内存位置的访问,或者现在是某个与之前存在的完全不同的对象的一部分。这通常会导致程序的不正确行为(a.k.a,“错误”),特别难以诊断。

Shouldn't it have thrown an exception in the below case since the object Test was destroyed?

要求每个程序检测悬挂引用或指针的使用会对大多数程序的性能产生巨大的不利影响。在大多数 CPU 架构上,通过引用获取某个变量的值可能是一条机器指令。检测引用是否有效可能需要程序执行数十或数百条指令。

语言标准将悬挂引用或指针的使用视为undefined behavior。这是他们的说法,你不应该这样做,但有责任确保你的程序不这样做。