在函数内删除对象:丑陋、容易出错、效率低下,而且通常不是异常安全的

Delete object inside a function: ugly, error-prone, inefficient, and usually not exception-safe

根据以下文章: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;
}

问题:


按照建议我做了以下事情:

TiXmlDocument doc(xmlFile.c_str());
bool loadOkay = doc.LoadFile();
TiXmlHandle hdl(&doc);

我开始认为在 c++ 中使用动态内存就像 java 和 c# 不是一个好的做法(应该以负责任的方式使用)。如果没有真正的理由使用它,那么就不要使用它。如果处理不当,将导致难以追踪的内存泄漏。


要么在没有 new 的情况下创建你的对象:

void func()
{
    X p;
    // use p
}

或者如果一定要用new(比如大对象)那就用智能指针:

void func()
{
    std::unique_ptr<X> p(new X);
    // use p
}

问题已解决!

这仍然很丑陋(在我看来),而且肯定容易出错、效率低下并且不是异常安全的。如果在此函数期间抛出异常,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

回答最后一个问题:使用析构函数释放由 class 实例管理的资源,而不是函数调用中使用的瞬态资源。同样,您通常应该使用 RAII 类型作为成员变量来自动管理这些资源,这样您就不需要自己编写析构函数了。