为什么删除 TStringList 指针会抛出异常?

Why does deleting a TStringList pointer throw an exception?

我正在使用 Embarcadero C++ Builder。

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

我一直愉快地将此代码用作 32 位应用程序,并将其转换为 64 位应用程序,现在我在尝试删除 TStringList 时遇到 "Invalid Pointer Operation" 异常。有什么想法吗?

奇怪的是,我在使用字符指针(使用 new 创建堆内存 space)和 delete 操作的另一个函数中遇到了同样的麻烦。我最终为该函数创建了一个带有堆栈 space 的本地缓冲区,但我坚持使用这个缓冲区,因为我想使用 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;
}

如评论中所述,您的代码中存在逻辑错误,导致您 delete List 两次,或完全泄漏。

尝试更像这样的东西:

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;
}