如果正在删除其对象,正在运行的方法会发生什么?

时间:2017-11-16 21:16:06

标签: c++ oop c++11

我是StackOverflow的新手,我的第一个问题是当我删除它的对象时,运行方法会发生什么?在我删除旧对象后,在方法中创建新对象时会发生什么?

下面有一个小代码片段来澄清我的问题。 (用C ++ 11编程)

// Declaration and Definition of the class
class MyClass{
private:
    static int counterFromClass = 0;
    int counterFromObject;
public:
    MyClass() {
        counterFromObject = 0;
    }
    void ~MyClass() {}
    void doSomething();
};

// Somewhere in the code a new object of the class is generated like this:
MyClass object = new MyClass();

// Then the method is called:
object->doSomething();

// Definition of the method
void MyClass::doSomething() {
    this->counterFromObject++;
    delete object;
    MyClass object = new MyClass();
    this->counterFromClass++;
}

如果现在调用方法doSomething()

  1. 方法会一直运行到结束还是会中断?
  2. 如果它一直运行到结束,它是否属于已删除的object或新的?{1}}?两个对象(已删除对象和新对象)具有相同的名称。
  3. 如果被打断,会发生什么?或者这种行为是否未定义?
  4. 到目前为止,我已经完成了,似乎该方法将运行到最后并执行所有命令,只要它们不影响已删除的对象。例如。允许操作像counterFromClass这样的静态变量。并且似乎也可以在方法内操作对象的数据成员,如counterFromObject,只要它们在delete命令之前被操作。

    嗯,代码有效,但我知道它不是最好的编程风格。所以我刚开始研究一个更好的解决方案,但我仍然很好奇究竟发生了什么,以及我的思想是否正确。我很感激你的答案。

    如果问题有问题,请告诉我,因为我对StackOverflow上的问题并不熟悉。
    谢谢:))

4 个答案:

答案 0 :(得分:2)

让我们一步一步地采取这个功能:

void MyClass::doSomething() {
    this->counterFromObject++;

这是完全合法的。但你知道的。

    delete object;

再次,完全合法。但是,在此之后, 作业是确保没有代码再次尝试访问object指针后面的对象。问题是,当前运行的方法的this指针包含死对象地址的副本; this指针悬空。因此,以任何方式显式或隐式地解除引用this将立即产生未定义的行为。

    MyClass* object = new MyClass();    //I added the missing * to the type, we are not using java here.

这不会取消引用this,所以完全没问题。请注意,这对当前运行的方法没有任何影响。 this指针悬空,没有办法重新分配。

    this->counterFromClass++;

正式地,这是未定义的行为,因为您正在解除引用this。但是,由于counterFromClass是静态的,因此很可能不会使您的进程崩溃,因为已编译的代码实际上不会访问this后面的内存。然而,编写this->意味着你有未定义的行为,所以你的进程可能会崩溃,或者你的编译器可能只是抛弃这个语句!它是否这样做只取决于编译器是否是智能的足以证明你在这里有不明确的行为。
(正如MartinBonner所发现的,标准在第9.4节中说,即使通过this->访问静态成员,也会评估对象表达式,这意味着根据标准实际取消引用悬空this指针并且取消引用悬空指针是未定义的行为。)

因此,在方法运行时删除一个对象是绝对可以的,并且有一些用途(一个例子是引用计数对象,当它的引用计数降为零时自杀)。但是,如果您需要这样做,

  1. 写一条警告评论,说明您可能正在删除this对象,

  2. 请务必立即返回。

答案 1 :(得分:0)

删除对象会使this指针无效。可能(但不是100%)创建一个新对象会给你一个新指针。但是在上面的代码中,this指针并没有神奇地改变为新对象。您有未定义的行为。

答案 2 :(得分:0)

对象的代码和分配空间分开存储。代码只在二进制文件中存储一次(并在执行二进制文件时加载到内存中)。对象是在内存,堆或堆栈中动态创建的。方法的代码使用this指针操作对象的数据(这是方法的'不可见'参数,可以通过在方法中显式写this来访问,或者隐式使用访问成员时。)

如果删除对象,则运行函数不会发生任何事情。它将继续运行并执行命令。 this指针在执行期间不会改变(因为,如前所述,它就像是按值复制的函数的参数)。但是,如果删除该对象,则很可能不会指向任何有用的对象。所以:

  • 使用this指针将为您提供SEGFAULT,因为您不再访问不属于该应用程序的内存
  • 或将访问应用程序中的一些随机内存,从而导致未定义的行为

所以回答你的问题:

  1. 不,它没有被打断。它一直在执行这个功能。
  2. 它不属于任何东西,只对this指向的数据进行操作。你的第二个新版本不能保证给你相同的指针值(内存地址)。
  3. 它没有被打断,但是如果你继续访问对象成员,几乎会导致未定义的行为。

答案 3 :(得分:-1)

从技术上讲,这是未定义的行为。然而,在实践中发生的是,大多数编译器实现将方法指令存储在内存中的相同位置,无论方法是否是静态的,就像类的静态成员变量存储在内存中的相同位置一样。这是因为方法逻辑在不同实例之间不同。从实例到实例存储在不同内存中的是非静态成员变量。

此外,在编译时,会向函数添加隐式参数,这是指向类实例的指针。这就是编译函数通过隐式“this”指针访问成员变量的方式。

因此,当您在执行函数的过程中删除对象时,它将继续执行,直到它尝试使用非静态成员变量,该变量存储在专门为该对象分配的内存中,现在已取消分配。此时它可能会继续执行,如果内存没有被回收,或者如果你很幸运,程序将崩溃。