变量或对象的内存在程序结束时自动终止完成,而不是我们使用析构函数的原因?

时间:2014-06-22 07:51:37

标签: c++ oop constructor destructor

在下面的程序中,我们在本地范围内创建Circle对象,因为我们没有使用new关键字。我们知道变量或对象的内存在程序结束时自动终止,而不是我们使用destruct的原因?

#include<iostream>
using namespace std;     
class Circle //specify a class
{
    private :
        double radius; //class data members
    public:
        Circle() //default constructor
        {
            radius = 0;
        }           
        void setRadius(double r) //function to set data
        {
            radius = r;
        }
        double getArea()
        {
            return 3.14 * radius * radius;
        }
        ~Circle() //destructor
        {} 
};

int main()
{
    Circle c; //defalut constructor invoked   
    cout << c.getArea()<<endl;     
    return 0;
}

3 个答案:

答案 0 :(得分:2)

假设内存是无限资源非常危险。想想一个需要全天候运行并以高速率收听数据馈送的实时应用程序(让“每秒1000条消息”)。每条消息大约1KB,每次为每条消息分配一个新的内存块(显然在堆中)。总而言之,我们每天需要大约82 GB。如果你不管理你的记忆,现在你可以看到会发生什么。我不是在谈论复杂的内存池技术或类似技术。通过简单的算术计算,我们可以看到我们无法将所有消息存储在内存中。这是您考虑内存管理的另一个例子(从分配和释放的角度来看)。

答案 1 :(得分:2)

首先,您不需要显式定义析构函数。一个将由编译器自动定义。如果您按照3的规则执行,或者如果您声明以下任何内容,则按照c ++ 11中的5进行注释:复制构造函数,复制赋值,移动构造函数(c ++ 11),移动赋值(c) ++ 11)或析构函数你应该明确定义所有这些。

继续前进。过度简化,RAII原则规定必须解除分配的每个资源。此外,在分配的每个资源上必须存在一个且只有一个所有者,一个负责处理资源的对象。这是资源管理。这里的资源可以指在使用前必须初始化并在使用后释放的任何内容,例如动态分配的内存,系统处理程序(文件处理程序,线程处理程序),套接字等。实现的方式是通过构造函数和析构函数。如果您的对象负责销毁资源,那么当您的对象死亡时应该销毁该资源。这里有析构函数。

你的例子并不是那么好,因为你的变量存在于main中,所以它将适用于整个程序。

考虑函数内的局部变量:

int f()
{
    Circle c; 
    // whatever    
    return 0;
}

每次调用函数f时,都会创建一个新的Circle对象,并在函数返回时将其销毁。

现在作为练习考虑以下程序的错误:

std::vector foo() {
  int *v = new int[100];

  std::vector<int> result(100);

  for (int i = 0; i < 100; ++i) {
    v[i] = i * 100 + 5;
  }


  //
  //  .. some code
  //

  for (int i = 0; i < 100; ++i) {
    result.at(i) = v[i];
  }

  bar(result);

  delete v;

  return result;
}

现在这是一个非常无用的程序。但是从正确性的角度考虑它。您在函数的开头分配一个100个int的数组,然后在函数的末尾释放它们。所以你可能认为这没问题,也没有发生内存泄漏。你不能错。还记得RAII吗?谁负责该资源?函数foo?如果是这样的话,它的工作非常糟糕。再看一遍:

std::vector foo() {
  int *v = new int[100];

  std::vector<int> result(100); <-- might throw

  for (int i = 0; i < 100; ++i) {
    v[i] = i * 100 + 5;
  }

  //
  //  .. some code              <-- might throw in many places
  //

  for (int i = 0; i < 100; ++i) {
    result.at(i) = v[i];       <-- might (theoretically at least) throw
  }

   bar(result);                <-- might throw


  delete v;

  return result;
}

如果函数抛出任何点,则不会到达delete v,并且永远不会删除资源。因此,您必须有一个明确的资源所有者负责销毁该资源。您知道什么构造函数和析构函数将帮助我们:

class Responsible() { // looks familiar? take a look at unique_ptr
  private:
    int * p_ = nullptr;
  public:
    Responsible(std::size_t size) {
      p_ = new int[size];
    }
    ~Responsible() {
      delete p_;
    }
    // access methods (getters and setter)
};

所以程序变成:

std::vector foo() {
  Responsible v(100);      

  //
  //  .. some code
  //

  return result;
}

现在即使该函数将抛出资源也将得到妥善管理,因为当发生异常时,堆栈被解除,即所有局部变量都被很好地销毁了......幸运的是,Responsible的析构函数将会被调用。

答案 2 :(得分:0)

好吧,有时你的对象可能有指针或需要解除分配的东西等。

例如,如果您在Circle类中有一个poiner,则需要释放它以避免内存泄漏。

至少这是我所知道的。