2016-07-27 2 views
0

Я использую Embarcadero C++ Builder.Почему удаление указателя TStringList вызывает исключение?

У меня есть функция, которая объявляет TStringList, использует ее во всей функции, затем delete s объект в конце функции.

Я успешно использовал этот код в качестве 32-разрядного приложения и преобразовал его в 64-разрядное приложение, и теперь я получаю исключение «Invalid Pointer Operation» при попытке удалить 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; 
} 
+3

Поскольку вы уже удалили 'List', в вашем' try' -задаче? 'List-> LoadFromFile(); delete List; 'кажется довольно глупым, когда вы повторно используете' List' в блоке после 'catch'. –

+1

У вас в этом коде есть ошибки-после -delete и double -delete, а также утечка памяти. Почему вы 'delete'ing' List' в блоке 'try'? Вы, очевидно, хотите, чтобы он придерживался, чтобы вы могли выполнять операции в цикле 'for' позже. Кроме того, если исключение * * выбрано из блока 'try' и поймано,' List' фактически не будет 'delete'ed. Возможно, более важный вопрос здесь заключается в том, почему вы динамически выделяете «Список» вообще, поскольку, по-видимому, это никогда не должно пережить эту функцию? Просто положите его в стек, и проблема решена. – acwaters

+0

@acwaters, что вы говорите о стеке, как правило, справедливо для чисто кода на C++, но это не чистый код. 'TStringList' - это потомок TObject, а' TObject' может быть создан только в куче, а не в стеке. Это ограничение совместимости компилятора из-за того, что 'TObject' внедряется в Delphi Pascal, и все объекты класса Delphi основаны на куче. –

ответ

3

Как указано в комментариях, ваш код логических ошибок в нем, заставляя вас 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; 
} 
Смежные вопросы