use*_*738 0 c++ constructor destructor memory-leaks exception
这个问题是基于Scott Meyers在他的"更有效的C++"一书中提供的一个例子.考虑以下课程:
// A class to represent the profile of a user in a dating site for animal lovers.
class AnimalLoverProfile
{
public:
AnimalLoverProfile(const string& name,
const string& profilePictureFileName = "",
const string& pictureOfPetFileName = "");
~AnimalLoverProfile();
private:
string theName;
Image * profilePicture;
Image * pictureOfPet;
};
AnimalLoverProfile::AnimalLoverProfile(const string& name,
const string& profilePictureFileName,
const string& pictureOfPetFileName)
: theName(name)
{
if (profilePictureFileName != "")
{
profilePicture = new Image(profilePictureFileName);
}
if (pictureOfPetFileName != "")
{
pictureOfPet = new Image(pictureOfPetFileName); // Consider exception here!
}
}
AnimalLoverProfile::~AnimalLoverProfile()
{
delete profilePicture;
delete pictureOfPet;
}
Run Code Online (Sandbox Code Playgroud)
在他的书中,Scott解释说如果在对象的构造函数中抛出异常,那么该对象的析构函数将永远不会被调用,因为C++不能销毁部分构造的对象.在上面的示例中,如果调用new Image(pictureOfPetFileName)抛出异常,则永远不会调用类的析构函数,这会导致已分配的内容profilePicture泄露.
他描述了处理这个问题的许多不同方法,但我感兴趣的是成员变量theName.如果new Image构造函数中的任何一个调用引发了异常,那么这个成员变量是否会被泄露?斯科特说它不会被泄露,因为它是一个非指针数据成员,但如果析构函数AnimalLoverProfile从未被调用,那么谁会破坏theName?
析构函数AnimalLoverProfile从未被调用,因为此对象尚未构造,而析构函数theName将被调用,因为此对象已正确构造(即使它是尚未完全构造的对象的字段).通过使用智能指针可以避免任何内存泄漏:
::std::unique_ptr<Image> profilePicture;
::std::unique_ptr<Image> pictureOfPet;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,new Image(pictureOfPetFileName)抛出时,profilePicture对象将已经被构造,这意味着将调用它的析构函数,就像调用析构函数一样theName.