为什么删除TStringList指针会引发异常

Why does deleting a TStringList pointer throw an exception?

本文关键字:异常 指针 删除 TStringList 为什么      更新时间:2023-10-16

我正在使用Embarcadero C++Builder。

我有一个函数,它声明了一个TStringList,在整个函数中使用它,然后delete是函数末尾的对象。

我一直很高兴地将此代码作为32位应用程序使用,并将其转换为64位应用程序,现在我在尝试删除TStringList时遇到了"无效指针操作"异常。有什么想法吗?

奇怪的是,我在使用字符指针(使用new创建堆内存空间)和delete操作的另一个函数中遇到了同样的问题。我最终为该函数创建了一个具有堆栈空间的本地缓冲区,但由于我想使用TStringList对象,所以我一直使用这个缓冲区。

这是代码:

String ReadUserConfig(String ConfigString) {
    String UserConfigPath = AppDrive + "\DC\userconfig.csv";
    TStringList *List = new TStringList;

    if (FileExists(UserConfigPath)) { // file present, parse it
        try {
            List->LoadFromFile(UserConfigPath);
            delete List;
        }
        catch(...) {
            ShowMessage("Exception in ReadUserConfig()");
            return ReturnString;
        }
        for (int i = 0; i < List->Count; ++i) {
            String thisLine = List->Strings[i];
            /* search for ConfigString in this line */
            if ((thisLine.Pos(ConfigString) != 0) &&
                (thisLine.Pos("USER_CONFIG") != 0)) {
                /* grab everything right of ConfigString */
                thisLine = thisLine.SubString
                    (thisLine.Pos(ConfigString) + ConfigString.Length() + 1,
                    thisLine.Length());
                ReturnString = thisLine.Trim();
                i = List->Count;
            }
        }
    }
    delete List;  /* CAUSES INVALID POINTER EXCEPTION */
    return ReturnString;
}

如注释所述,您的代码中存在逻辑错误,导致deleteList两次,或者完全泄漏。

试试类似的东西:

String ReadUserConfig(String ConfigString) {
    String UserConfigPath = AppDrive + "\DC\userconfig.csv";
    try {
        TStringList *List = new TStringList;
        try {
            if (FileExists(UserConfigPath)) { // file present, parse it
                List->LoadFromFile(UserConfigPath);
                for (int i = 0; i < List->Count; ++i) {
                    String thisLine = List->Strings[i];
                    /* search for ConfigString in this line */
                    if ((thisLine.Pos(ConfigString) != 0) &&
                        (thisLine.Pos("USER_CONFIG") != 0)) {
                        /* grab everything right of ConfigString */
                        thisLine = thisLine.SubString(thisLine.Pos(ConfigString) + ConfigString.Length() + 1, thisLine.Length());
                        ReturnString = thisLine.Trim();    
                        break;
                    }
                }
            }
        }
        __finally {
            delete List;
        }
    }
    catch(const Exception &e) {
        ShowMessage("Exception in ReadUserConfig()n" + e.Message);
    }
    catch(...) {
        ShowMessage("Exception in ReadUserConfig()");
    }
    return ReturnString;
}

或者,使用std::auto_ptr(C++11之前)或std::unique_ptr(C++11及更高版本)而不是try/finally块:

#include <memory>
String ReadUserConfig(String ConfigString) {
    String UserConfigPath = AppDrive + "\DC\userconfig.csv";
    try {
        //std::auto_ptr<TStringList> List(new TStringList);
        std::unique_ptr<TStringList> List(new TStringList);
        if (FileExists(UserConfigPath)) { // file present, parse it
            List->LoadFromFile(UserConfigPath);
            for (int i = 0; i < List->Count; ++i) {
                String thisLine = List->Strings[i];
                /* search for ConfigString in this line */
                if ((thisLine.Pos(ConfigString) != 0) &&
                    (thisLine.Pos("USER_CONFIG") != 0)) {
                    /* grab everything right of ConfigString */
                    thisLine = thisLine.SubString(thisLine.Pos(ConfigString) + ConfigString.Length() + 1, thisLine.Length());
                    ReturnString = thisLine.Trim();    
                    break;
                }
            }
        }
    }
    catch(const Exception &e) {
        ShowMessage("Exception in ReadUserConfig()n" + e.Message);
    }
    catch(...) {
        ShowMessage("Exception in ReadUserConfig()");
    }
    return ReturnString;
}