已删除的类实例上的方法仍有效吗?

时间:2015-06-04 03:59:25

标签: c++ class object memory instance

我在Visual C ++ 2010上有这段代码

#include <iostream>
#include <string>

using namespace std;

class Human {
private:
    int magic;
    int health;
    string name;
public:
    int GetMagic() const;
    int GetHealth() const;
    Human(int, string);
    ~Human();

};
//helper
int Human::GetHealth() const {
    cout <<"This returns Human::health" << endl;
    return Human::health;

}
int Human::GetMagic() const {
    cout <<"This returns this->magic"<< endl;
    return this->magic;

}

//con/destructor
Human::Human(int a, int b, string c): health(a), magic(b), name(c)
{
    cout<<c<<" is born!"<<endl;
}
Human::~Human() 
{
    cout <<this->name << " is killed!" << endl;
}

int main (){
    Human lucife(20,10,"Lucife");
    cout << lucife.GetHealth()<<endl;
    cout << lucife.GetMagic()<<endl;
    lucife.~Human();

    cout << lucife.GetHealth()<<endl;
    cout << lucife.GetMagic()<<endl;
    cout<<endl;


    lucife.~Human();

    system("pause");

}

当我运行它时:

Lucife is born!
This returns Human::health;
20
This returns this->magic
10
Lucife is killed!
This returns Human::health
20
This returns this->magic
10
 is killed!

我有3个问题:

  1. 在我杀死实例后,&#34; lucife&#34;第一次,为什么两个方法GetHealth()和GetMagic()仍然有效?
  2. 我第二次在实例上打电话给~Heart()&#34; lucife&#34;,为什么没有打印出来&#34; Lucife被杀了!&#34;像第一次?这到底发生了什么?名称值是否已删除?
  3. 返回Human :: health并返回此 - &gt;健康意味着同样的事情吗?我试过了,看到没有区别。我认为它们都会返回调用该方法的实例的健康状况(&#34; lucife&#34;在这种情况下)。
  4. 非常感谢你

4 个答案:

答案 0 :(得分:3)

您正在看到未定义行为的症状。

来自C ++标准:

  

12.4析构函数

     

...

     

15为对象调用析构函数后,该对象不再存在;如果为生命周期结束的对象调用析构函数,则行为未定义(3.8)。 [示例:如果显式调用自动对象的析构函数,并且该块随后以通常调用对象的隐式销毁的方式保留,则行为未定义。 - 结束示例]

答案 1 :(得分:1)

可能是内容仍然存在的原因(如果我错了,请纠正我。)

来自C++, Free-Store vs Heap

  

免费存储是两个动态内存区域之一,由new / delete分配/释放。对象生存期可以小于分配存储的时间;也就是说,免费存储对象可以在不立即初始化的情况下分配内存,并且可以在不立即释放内存的情况下销毁。在分配存储但在对象的生命周期之外的期间,可以通过void *访问和操纵存储,但是可以访问原始对象的非静态成员或成员函数,获取其地址或以其他方式操作

我同意@R Sahu的意见,你要做的事情是不确定的。

答案 2 :(得分:1)

我还在学习stackoverflow和发布在这里的人。奇怪的环境....

好的......首先,使用指向指向对象的指针,然后指向&#34; const&#34;声明和定义的变量...我不太确定你的目标是什么,但它们不匹配(以你使用它们的方式)。接下来,您不需要使用&#34;这个&#34;方法中的指针。

请记住,内存管理(使用C ++)是您的责任。如果你需要/想要调用析构函数,那么通过&#34; delete&#34;过程

Human * pLucifer = new Human(20,10,&#34; Lucifer&#34;);

cout&lt;&lt; pLucifer-&GT; GetHealth()&LT; GetMagic()&LT;

删除pLucifer;

忽略您作为&#34; Human&#34;收到的其他答案帖子。对象是在堆栈上创建的,即使您已明确调用析构函数,在函数终止之前也不会处理内存管理(在本例中为... main)。因此,在您明确调用析构函数(淘气!不要这样做)之后,您的数据仍可访问的原因是因为堆栈仍处于机智状态,无论您引用它(堆栈),您都是&#39 ;能够获得那里的数据。希望它有所帮助

答案 3 :(得分:1)

正如@R和@Rupesh所提到的,您看到的行为未定义。

但是,如果我可以向您提供更多解释,说明在特定环境中您的特定代码中发生了什么,可能就是这样。

  
      
  1. 在我杀死实例后,&#34; lucife&#34;第一次,为什么两个方法GetHealth()和GetMagic()仍然有效?
  2.   

首先,不要明确地调用您的对象destructor。 一旦你离开范围main,它将自动被触发。这从来都不是一个好习惯。

您仍然可以调用GetHealth()GetMagic()的原因是它们只是具有this的第一个隐藏参数的函数。

如果你看到

,你可能会感到惊讶
class AAA
{
public:
    void f() { std::cout << "Hello world" << std::endl; }
}

((AAA*) 0)->f();

能够编译并运行正常。 (取决于您的环境)。

因此,即使您在范围中间显式调用了析构函数,希望它会彻底破坏内部的所有内容,您仍然可以在不解除引用this的情况下到达nullptr并成功提供{{1运气好的预期功能。

  
      
  1. 我第二次在实例上打电话给~Heart()&#34; lucife&#34;,为什么没有打印出来&#34; Lucife被杀了!&#34;像第一次?到底是什么   发生在这里?名称值是否已删除?
  2.   

这是因为当this被解雇时,Human::~Human()的析构函数也会被触发,最终整理

  
      
  1. 返回Human :: health并返回此 - &gt;健康意味着同样的事情吗?我试过了,看到没有区别。我想两个   它们返回调用该方法的实例的运行状况   (&#34; lucife&#34;在这种情况下)。
  2.   
不,他们是不同的。 但是,在您的代码中,std::string只是转换为Human::health,因为您在类this->health中使用了它。