根据以下文章:Why isn’t the destructor called at the end of scope?
使用new创建对象然后在同一范围的末尾删除它的代码是丑陋的,容易出错,效率低下,并且通常不是异常安全的。例如:
void very_bad_func() // ugly, error-prone, and inefficient
{
X* p = new X;
// use p
delete p; // not exception-safe
}
我正在创建一个TiXmlDocument
类型的对象,并在函数末尾删除它。
void DataLoader::readXmlFile(const string & file)
{
TiXmlDocument *doc = new TiXmlDocument(file.c_str());
bool loadOkay = doc->LoadFile();
TiXmlHandle hdl(doc);
//work is done in here
if(loadOkay)
{
TiXmlElement * pRoot = hdl.FirstChildElement().Element();//.FirstChildElement().Element();
parseFile(pRoot);
}
else
{
cout <<"Error: "<< doc->ErrorDesc()<<endl;
}
//deallocate doc
delete doc;
}
DataLoader::~DataLoader() {}
析构函数以确保在离开函数范围后删除对象?无需明确删除delete doc
。根据建议我做了以下事情:
TiXmlDocument doc(xmlFile.c_str());
bool loadOkay = doc.LoadFile();
TiXmlHandle hdl(&doc);
我开始认为在c ++中使用动态内存就像java和c#一样不是一个好习惯(应该以负责任的方式使用)。如果没有真正的原因可以使用它,那就不要。如果处理不当,将导致内存泄漏,难以追踪。
答案 0 :(得分:7)
创建没有new的对象:
void func()
{
X p;
// use p
}
或者如果你必须使用new(例如,它是一个大对象),那么使用智能指针:
void func()
{
std::unique_ptr<X> p(new X);
// use p
}
问题解决了!
答案 1 :(得分:3)
那仍然很丑陋(在我看来),当然容易出错,效率低下,而且不是例外安全。如果在此函数期间抛出异常,则delete
不会发生,并且您将泄漏内存。
在这种情况下,根本不需要new
;使用一个自动变量,当函数退出时会自动销毁,无论是到达结尾,返回还是抛出。
TiXmlDocument doc(file.c_str());
如果由于某种原因确实需要动态分配,那么使用智能指针或其他RAII类型来获得相同的自动行为:
auto doc = std::make_unique<TiXmlDocument>(file.c_str()); // C++14 or later
std::unique_ptr<TiXmlDocument> doc(new TiXmlDocument(file.c_str())); // C++11
回答最后一个问题:使用析构函数释放由类实例管理的资源,而不是函数调用中使用的瞬态资源。同样,您通常应该使用RAII类型作为成员变量来自动管理这些资源,这样您就不需要自己编写析构函数。