在程序中经常需要为类的数据成员动态分配内存。可以在构造函数中使用 new 操作符来为对象成员分配空间。在这种情况下,必须提供适当的析构函数,在不需要该对象时释放内存。
比如下面有这么一个类定义:
[C++] 纯文本查看 复制代码 #include <iostream> // For stream I/O
#include <cstring> // For strlen() and strcpy()
using std::cout;
using std::endl;
// Put the CMessage class definition here (Listing 08_01)
//Listing 08_01
class CMessage
{
private:
char* pmessage; // Pointer to object text string
public:
// Function to display a message
void ShowIt() const
{
cout << endl << pmessage;
}
// Constructor definition
CMessage(const char* text = "Default message")
{
pmessage = new char[strlen(text) + 1]; // Allocate space for text
strcpy_s(pmessage, strlen(text) + 1, text); // Copy text to new memory
}
~CMessage(); // Destructor prototype
};
// Destructor to free memory allocated by new
CMessage::~CMessage()
{
cout << "Destructor called." // Just to track what happens
<< endl;
delete[] pmessage; // Free memory assigned to pointer
}
该类定义了一个字符串指针 pmessage 的数据成员 。在使用 new 给字符串提供内存后(一个数组),然后用 strcpy_s() 库函数将字符串复制到内存中。如果我们不提供析构函数,那么程序就不能释放分配的内存。进一步来讲,如果一个程序的函数里多次创建临时的 CMessage 对象,尽管在函数返回时会销毁该对象,但是被分配的内存并不会被释放。因此,每调用一次该函数,就有更多的空闲存储器内存被抛弃的 CMessage 对象占用。所以上面的 CMessage 析构函数里,使用了 delete 来删除分配的数组,注意 [ ] 符号是必须的。
下面是一个完整的测试实例,注意析构函数的输出:
[C++] 纯文本查看 复制代码
// Using a destructor to free memory
#include <iostream> // For stream I/O
#include <cstring> // For strlen() and strcpy()
using std::cout;
using std::endl;
class CMessage
{
private:
char* pmessage; // Pointer to object text string
public:
// Function to display a message
void ShowIt() const
{
cout << endl << pmessage;
}
// Constructor definition
CMessage(const char* text = "Default message")
{
pmessage = new char[strlen(text) + 1]; // Allocate space for text
strcpy_s(pmessage, strlen(text) + 1, text); // Copy text to new memory
}
~CMessage(); // Destructor prototype
};
// Destructor to free memory allocated by new
CMessage::~CMessage()
{
cout << "Destructor called." // Just to track what happens
<< endl;
delete[] pmessage; // Free memory assigned to pointer
}
int main()
{
// Declare object
CMessage motto("A miss is as good as a mile.");
// Dynamic object
CMessage* pM(new CMessage("A cat can look at a queen."));
motto.ShowIt(); // Display 1st message
pM->ShowIt(); // Display 2nd message
cout << endl;
// delete pM; // Manually delete object created with new
return 0;
}
输出结果:A miss is as good as a mile.
A cat can look at a queen.
Destructor called. 上面程序中创建了两个 CMessage 对象,但输出中只看到调用一次的析构函数,这是为什么?首先,编译器并不负责删除在空闲存储器(堆)中创建的对象。编译器之所以为 motto 这个对象调用析构函数,是因为它只是一个普通的自动对象,尽管该对象的数据成员占用的内存是由构造函数在空闲存储器中分配的。
pM 指向的对象就不同了。该对象并不是一个直接定义出来的自动对象,而是由 new 分配出来的,并令 pM 这个指针指向了它。上面说过,在空闲存储器中为对象分配内存,因此必须使用 delete 将其删除,因此 delete pM; 这条语句就不能少。加上去该条语句之后,就可以看到两条析构函数的输出了。
delete 释放 pM 指向 CMessage 对象的内存,由于该对象也定义了析构函数,因此 delete 会在释放该对象之前调用该对象的析构函数以释放该对象成员所申请占用的内存,这样就确保了类成员动态分配的内存和象自身的内存都得到释放。 |