2016-07-27 4 views
0

私はEmbarcadero C++ Builderを使用しています。TStringListポインタを削除すると例外がスローされるのはなぜですか?

私はTStringListを宣言し、関数全体でそれを使用する関数を持っています。そして、関数の最後にオブジェクトdeleteがあります。

このコードを幸せに32ビットアプリケーションとして使用していて、これを64ビットアプリケーションに変換しましたが、TStringListを削除しようとすると「無効なポインタ操作」例外が発生します。何か案は?

私は文字ポインタ(ヒープメモリ空間を作成するためにnewを使用)と操作deleteを使用する別の関数で同じ問題を抱えていました。私は、その関数のスタックスペースを持つローカルバッファを作成してしまったが、私はTStringListオブジェクトを使用したいので、この1つに固執している。あなたのコードは、二回deleteListにあなたを引き起こし、それにロジックのバグを持っている、またはそれを完全に漏れて、コメントで述べたように

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();リストを削除する; '' catch'の後のブロックで 'List'を繰り返し使用しているとき、かなり愚かなようです。 –

+1

このコードでuse-after -deleleteとdouble -delete'バグとメモリリークがあります。 'try'ブロックで' List'を 'delete'しているのはなぜですか?後で 'for'ループで操作を行うことができるように、あなたはそれを固執しておきたいと思います。さらに、 'try'ブロックから例外がスローされ捕捉された場合、' List'は実際には 'delete'されません。しかし、ここで重要なのはおそらく、なぜこの関数を永久に失うことはないと思われるので、あなたは動的に 'List'を割り当てているのでしょうか?スタックに置くだけで問題は解決します。 – acwaters

+0

@acwatersスタックについて言うことは、純粋なC++コードでは一般的に当てはまりますが、これは純粋なコードではありません。 'TStringList'は' TObject'子孫であり、 'TObject'はスタックではなくヒープ上でのみ構築できます。これは、 'TObject'がDelphi Pascalに組み込まれているため、コンパイラの互換性の制限です。すべてのDelphiクラスオブジェクトはヒープベースです。 –

答えて

3

:ここ

はコードです。

より代わりにこのような何か試してみてください:

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

または、代わりにtry/finallyブロックのstd::auto_ptr(事前C++ 11)またはstd::unique_ptr(C++ 11以降)を使用します。

#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; 
} 
関連する問題