为什么即使在对象被删除后我仍然可以访问成员函数?

2021-12-11 00:00:00 function object c++ member delete-operator

我是 C++ 的新手,到目前为止,当您对指向在堆上创建的内容的指针调用 delete 时,我学到了什么,然后该指针指向的任何内容都会被擦除并释放内存,对吗?

I'm new to C++ and from what I learned so far when you call delete on a pointer that points to something created on the heap then whatever is pointed by that pointer gets erased and the memory is freed, right?

然而,当我在一个简单的类上尝试这个时:

However when I tried this on a simple class:

class MyClass
{
    int _Id;
public:
    MyClass(int id) : _Id(id)
    {
        std::cout << "$Constructing the damn thing! " << _Id << std::endl;
    }
    ~MyClass()
    {
        std::cout << "?Destructing the damn thing! " << _Id << std::endl;
    }
    void Go_XXX_Your_Self()
    {
        std::cout << "%OooooooooO NOOOOOO! " << _Id << std::endl;
        delete this;
    }
    void Identify_Your_Self()
    {
        std::cout << "#Object number: " << _Id << " Located at: " << this << std::endl;
    }
};

这些只是一些愚蠢的测试来看看删除是如何工作的:

These are just some stupid tests to see how delete works:

int main()
{
    MyClass* MC1 = new MyClass(100);
    MyClass* MC2 = new MyClass(200);
    MyClass* MC3 = MC2;

    std::cout << MC1 << " " << MC2 << " " << MC3 << " " << std::endl;

    MC1->Identify_Your_Self();
    MC2->Identify_Your_Self();
    MC3->Identify_Your_Self();

    delete MC1;

    MC1->Identify_Your_Self();


    MC3->Go_XXX_Your_Self();

    MC3->Identify_Your_Self();


    delete MC2;

    MC2->Identify_Your_Self();

    MC2->Go_XXX_Your_Self();

    MC2->Identify_Your_Self();

    return 0;
}

输出如下:

$Constructing the damn thing! 100
$Constructing the damn thing! 200
0x3e3e90 0x3e3eb0 0x3e3eb0
#Object number: 100 Located at: 0x3e3e90
#Object number: 200 Located at: 0x3e3eb0
#Object number: 200 Located at: 0x3e3eb0
?Destructing the damn thing! 100
#Object number: 0 Located at: 0x3e3e90
%OooooooooO NOOOOOO! 200
?Destructing the damn thing! 200
#Object number: 4079248 Located at: 0x3e3eb0
?Destructing the damn thing! 4079248
#Object number: 4079280 Located at: 0x3e3eb0
%OooooooooO NOOOOOO! 4079280
?Destructing the damn thing! 4079280
#Object number: 4079280 Located at: 0x3e3eb0

那么,我的问题是,为什么即使在对象被删除后我仍然能够调用 Go_XXX_Your_Self() 和 Identification_Your_Self()?

So, my question is, why I'm still able to call Go_XXX_Your_Self() and Identify_Your_Self() even after the object was deleted?

这是在 C++ 中的工作方式吗?(删除后还有吗?)

Is this how it works in C++? (is there even after you delete it?)

你也可以检查一下它是否在那里吗?(我知道理论上是不可能的,但我很想知道那里有哪些方法)

Also can you check to see if it's not there? (I know theoretically is not possible but I'm curious to see what methods are out there)

推荐答案

那么,我的问题是,为什么即使在对象被删除后我仍然能够调用 Go_XXX_Your_Self() 和 Identification_Your_Self()?

So, my question is, why I'm still able to call Go_XXX_Your_Self() and Identify_Your_Self() even after the object was deleted?

因为未定义的行为.

这是在 C++ 中的工作方式吗?(删除后还有吗?)

Is this how it works in C++? (is there even after you delete it?)

因为未定义的行为.不能保证它在其他实现上也能正常工作.同样,未定义行为.

Because of undefined behavior. There is no guarantee that it will work the same on other implementations. Again, undefined behavior.

你也可以检查一下它是否在那里吗?(我知道理论上是不可能的,但我很想知道那里有哪些方法)

Also can you check to see if it's not there? (I know theoretically is not possible but I'm curious to see what methods are out there)

delete MC1;
MC1 = nullptr;

通过在 delete 之后将指针设置为 nullptr,运行时最有可能检测到您正在访问一个无效的,您没有权利-使用位置.此外,通过对所有适用的指针认真执行此操作,您可以检查对象是否有效(如果非nullptr 则有效).

By setting the pointer to nullptr after deleteing it, the runtime is most likely to detect that you are accessing an invalid, you-have-no-right-to-use location. Also, by diligently doing this for all applicable pointers, you have the ability to check if the object is valid or not (valid if non-nullptr).

if(my_ptr) {
   // my_ptr is most possibly valid (though you can still go wrong)
   // use my_ptr
}

同样,当原始指针尚未初始化为某个有效地址时,您也应该将它们设置为 nullptr.

Similarly, you should also set raw pointers to nullptr when they aren't yet initialized to some valid address.

MyClass* some_ptr = nullptr;
...

但同样,如果您可以访问现代 C++11 工具,最好根本不使用原始指针,而只使用 std::unique_ptrstd::shared_ptr (取决于您所需的语义).在未来的 C++ 标准修订版中,您可能还想使用 建议的 std::exempt_ptr 这是一个非拥有的、仅观察的指针包装器.

But again, if you have access to modern C++11 facilities, it's much better not to use raw pointers at all, and just use std::unique_ptr or std::shared_ptr (depending on your required semantics). And on future C++ standard revisions, you may also want to use the proposed std::exempt_ptr which is a non-owning, observe-only pointer wrapper.

相关文章