当有大量内存分配时,如何处理C++编程中的异常

How to deal with Exceptions in C++ programming when there are a lot of memory allocation

本文关键字:处理 C++ 编程 异常 何处理 内存 分配      更新时间:2023-10-16

我是C++程序领域的新手,我读了《更有效C++》一书。有一个关于如何处理C++异常的特定部分。就第 10 项而言,作者声称我们应该避免构造函数中的内存泄漏,如以下示例所示。

BookEntry::BookEntry(const string& name, const string& address, 
const string& imageFileName, 
const string& audioClipFileNmae):theName(name), theAddress(address), 
theImage(0), theAudioClip(0) {
try {
if (imageFileName != "") {
theImage = new Image(imageFileName);
}
if (audioClipFileName != "") {
theAudioClip = new AudioClip(audioClipFileName);
}
}
catch (...) {
delete theImage;
delete theAudioClip;
}

这样,当创建图像或音频剪辑时出现错误时,我们可以避免源泄漏。我的问题是,如果有很多函数包含内存分配,如下所示。

void BookEntry::test1() {
float *A = new float[1000];
float *B = new float[1000];
....
delete [] A;
delete [] B;
}

我是否必须使用 try catch 结构来处理内存泄漏的危险?通常,我更喜欢只测试指针 A 和指针 B 是否为空指针,如果分配失败,我将立即中止程序。

你可能误解了这本书所说的"内存泄漏"是什么意思。分配失败可能是内存泄漏的最终结果,但这两件事并不相同。

这本书所讨论的是如果构造函数失败会发生什么AudioClip。不是AudioClip的内存分配,而是AudioClip构造函数。因为请记住,构造函数只有一种方法来发出失败信号:引发异常。

如果它引发,并且BookEntry构造函数调用的调用堆栈中的某人捕获了该异常,则以前分配的theImage永远不会被清理。BookEntry的构造函数从未成功完成,因此永远不会调用其析构函数(因为该对象从未存在过,因此无法删除它(。

这就是为什么现在(又名:C++11 后(,我们会将这些分配的成员存储在智能指针中。虽然永远不会调用BookEntry的析构函数,但调用其任何成功构造的子对象的析构函数。因此,如果theImage是一个unique_ptr<Image>,它将调用其析构函数,这将删除它所持有的Image

通常,我更喜欢只测试指针 A 和指针 B 是否为空指针,如果分配失败,我将立即中止程序。

然后,内存分配失败的异常对您来说甚至更好,因为您不必测试任何内容。您只需让分配失败异常到达main,您的程序就会终止。

但是,上述问题与分配失败异常无关。