Я использую Embarcadero C ++ Builder.
У меня есть функция, которая объявляет TStringList
, использует его во всей функции, затем delete
s объект в конце функции.
Я с удовольствием использовал этот код в качестве 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;
}
Как указано в комментариях, в вашем коде есть логические ошибки, заставляющие вас 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;
}
Других решений пока нет …