在下面的程序中,我们在本地范围内创建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;
}
答案 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,则需要释放它以避免内存泄漏。
至少这是我所知道的。