为什么删除 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;
}
我正在使用 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;
}