Home > OS >  Why are member variables modifyable even after object is destroyed?
Why are member variables modifyable even after object is destroyed?

Time:12-10

If the shared_ptr is destroyed, what happens to "this" if captured in a lambda to be run on a thread? Shouldn't it have thrown an exception in the below case since the object Test was destroyed before the thread could finish running.

#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;
}

Output is

Create Test
Destroyed
Destroy Test
3

How is the lambda able to access testInt of a destroyed object ?

CodePudding user response:

In practice, The hardware that executes your program knows nothing about objects or member variables or references or pointers. What was a variable in your C source code becomes a virtual memory location in the executable, and what was a reference or a pointer becomes a virtual memory address. When an object is "destroyed" by your program, that means nothing to the machine. The program just stops using that part of virtual memory for that purpose, and if the program continues to run, it quite likely will re-allocate that memory for some other purpose soon after.

If your program keeps a dangling reference/pointer to an object that previously was "destroyed," then any access through that pointer/reference will be an access to a memory location that either now is unused, or now is part of some entirely different object from the one that was there before. This typically leads to incorrect behavior of the program (a.k.a., "bugs") that can be especially difficult to diagnose.

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

Requiring every program to detect the use of a dangling reference or pointer would have a huge, detrimental impact on the performance of most programs. To fetch the value of some variable through a reference, on most CPU architectures, might be a single machine instruction. Detecting whether the reference was valid could require the program to execute tens or hundreds of instructions.

The language standard deems use of a dangling reference or pointer to be undefined behavior. That's their way of saying, you shouldn't do it, but it's your responsibility to ensure that your program doesn't do it.

  • Related