标签:避免在析构函数中编写代码 智能指针 内存泄露
上篇文章中,我们介绍了为什么应该彻底避免编写拷贝构造函数和赋值操作符。今天这篇我们讨论下为什么应该避免在析构函数中编写代码。即让析构函数为空。
例如:
virtual ~MyClass()
{
}需要编写析构函数可能有如下几个原因:
virtual ~ScppAssertFailedException() throw ()
{
}
class PersonDescription
{
public:
PersonDescription(const char* first_name, const char* last_name)
: first_name_(NULL), last_name_(NULL)
{
if(first_name != NULL)
first_name_ = new string(first_name);
if(last_name != NULL)
last_name_ = new string(last_name);
}
~PersonDescription()
{
delete first_name_;
delete last_name_;
}
private:
PersonDescription(const PersonDescription&);
PersonDescription& operator = (const PersonDescription&);
string* first_name_;
string* last_name_;
};
class PersonDescription
{
public:
PersonDescription(const char* first_name, const char* last_name)
: first_name_(NULL), last_name_(NULL)
{
if(first_name != NULL)
first_name_ = new string(first_name);
if(last_name != NULL)
last_name_ = new string(last_name);
}
private:
PersonDescription(const PersonDescription&);
PersonDescription& operator = (const PersonDescription&);
string* first_name_;
string* last_name_;
};
假设我们决定增加安全检查,检查调用者是否提供了名字和姓氏:
class PersonDescription
{
public:
PersonDescription(const char* first_name, const char* last_name)
: first_name_(NULL), last_name_(NULL)
{
<span style="color:#ff0000;">SCPP_ASSERT(first_name != NULL ,"First name must be provided");
first_name_ = new string(first_name);
SCPP_ASSERT(last_name != NULL ,"Last name must be provided");
last_name_ = new string(last_name);</span>
}
~PersonDescription()
{
delete first_name_;
delete last_name_;
}
private:
PersonDescription(const PersonDescription&);
PersonDescription& operator = (const PersonDescription&);
string* first_name_;
string* last_name_;
};
因此,在前面的例子当中,如果我们假设提供了名字却没有提供姓氏,表示名字的字符串将被分配内存,但永远不会被删除,因此导致了内存泄露。但是,情况还不至于无可挽回。更进一步观察,如果我们有一个包含了其他对象的对象,一个重要的问题是:哪些析构函数将被调用?哪些析构函数将不被调用?
以下是用一个小试验来说明:
class A
{
public:
A()
{
cout<<"Creating A"<<endl;
}
~A()
{
cout<<"Destroying A"<<endl;
}
};
class B
{
public:
B()
{
cout<<"Creating B"<<endl;
}
~B()
{
cout<<"Destroying B"<<endl;
}
};
class C : public A
{
public:
C()
{
cout<<"Creating C"<<endl;
Throw "Don't like C";
}
~C()
{
cout<<"Destroying C"<<endl;
}
private:
B b_;
};
int main()
{
cout<<"Testing throwing from constructor."<<endl;
try{
C c;
}catch(...)
{
cout<<"Caught an exception."<<endl;
}
return 0;
}
Testing throwing from constuctor. Creating A Creating B Creating C Destroying B Destroying A Caught an exception.
class PersonDescription
{
public:
PersonDescription(const char* first_name, const char* last_name)
: first_name_(NULL), last_name_(NULL)
{
SCPP_ASSERT(first_name != NULL ,"First name must be provided");
first_name_ = new string(first_name);
SCPP_ASSERT(last_name != NULL ,"Last name must be provided");
last_name_ = new string(last_name);
}
~PersonDescription()
{
delete first_name_;
delete last_name_;
}
private:
PersonDescription(const PersonDescription&);
PersonDescription& operator = (const PersonDescription&);
<span style="color:#ff0000;">scpp::ScopedPtr<string> first_name_;
scpp::ScopedPtr<string> last_name_;</span>
};
总结:
从构造函数中抛出异常时为了避免内存泄露,在设计类的时候,使析构函数保持为空函数。
标签:避免在析构函数中编写代码 智能指针 内存泄露
原文地址:http://blog.csdn.net/kerry0071/article/details/38011067