0

私はユーザーにテキストファイルの名前を尋ねるプログラムを持っています。テキストファイルを開いてそれを使って処理(読み取り、書き込み)を行い、ファイルを閉じてプログラムを終了します。

Program.h

class Program
{
     char* fileName;
public:
     Program();
     ~Program();
     void ReadFile(void);
};

Program.cpp

Program::Program(){
     //contstructor
     fileName=NULL;
}

Program::~Program(){
     cout << "in destructor" ;
     delete []fileName;
}

void Program::ReadFile(void){
     fileName = new char[40];

     cout <<"Please enter the name of the file to open: ";
     cin.clear();
     cin.getline(fileName, 40);

     ifstream file (fileName);

     if(file.is_open()){
          //do stuff
     }
     file.close();
}

現在delete []fileName;、デストラクタを挿入すると、画面に「in destructor」と出力されますが、fileNameは削除されません。fileNameが削除された後に取得して挿入するdelete []fileName;と、なぜですか。ReadFile()file.close()

私のプログラムの残りの部分は完全に機能するため、そのコードは貼り付けられません。メモリリークを取り除こうとしていますが、問題が発生しているのはfileNameだけなので、fileNameが使用されているコードのみを貼り付けました。

どんな助けでも大歓迎です。

追加情報:これを作成するためにVisual Studioを使用しており、メモリリーク検出を使用しています。これはそれが出力するものです:

検出されたメモリリーク!
オブジェクトのダンプ->
{132}通常のブロック(0x005D49A0、長さ40バイト)。
データ:6E 61 6D 65 73 2E 74 78 74 00 CD CD CD
CDCDCDオブジェクトのダンプが完了しました。
プログラム'[10772]program1.exe:Native'がコード0(0x0)で終了しました。

delete []fileName;それが私がうまくいかなかったと思う理由です。

また、これはどのようにint main()見えるかです

int main(){
     Program abc;
     abc.ReadFile();
}

ああ、Program.hは変更できません。.cppのみを変更できます。これは私の要件の一部です。

4

3 に答える 3

3

ファイル名がreadFileでのみ使用されている場合は、それをProgramクラスから削除し、その関数で自動変数にすることをお勧めします。

void Program::ReadFile(void){
     char fileName[40];
     ...
     file.close();
     // no delete [] necessary
}

あなたの問題はに関連している可能性があります

  1. コンストラクターでファイル名をnullptrに初期化していない
  2. コピーc-tor、代入演算子を定義していません
  3. readFileの古いファイル名を削除していません

したがって、メンバー変数をメソッドの自動変数として使用しないでください。

このメンバーを変数にする必要がある場合(配列に変更)、割り当てないでください。

class Program {
private:
  // char* filename;
  char filename[40];
}; 

[アップデート]

.hファイルが正しくありません-三つのルールに違反しています(http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)を参照)-コピーコンストラクターと代入演算子がありません。したがって、このヘッダーを変更できない方法でProgramクラスをコピーしないように注意してください。

更新後、プログラムに欠けているものは1つだけです。

delete[] filenamereadFileの先頭に次のいずれかを追加します。

void Program::ReadFile(void){
     delete [] filename;
     fileName = new char[40];

または(より良い)-readFileが呼び出されるたびに再割り当てしないでください:

void Program::ReadFile(void){
     if (!filename)
         fileName = new char[40];

または(最良)-このメモリをコンストラクタのみに割り当てます。

Program::Program() : filename(new char[40]) {}
void Program::ReadFile(void){
   // fileName = new char[40];
于 2012-10-20T23:37:42.530 に答える
1

あなたmainはここに投稿された通りであると確信していますか?グローバルに定義するだけの場合abc、メモリダンプレポートのメモリリーク後に解放され、無効なレポートが表示される可能性があります。デストラクタにブレークポイントを挿入して、デストラクタの前後でメモリリークが報告されているかどうかを確認できます。

于 2012-10-21T00:33:23.833 に答える
0

fileName明らかに削除されています:デストラクタのコードはそう言っています。ただし、表示しなかったコードがReadFile2回以上呼び出しを行うと、呼び出しごとReadFileに新しいメモリブロックが割り当てられ、前のブロックへのポインタが上書きされるため、クラスはメモリリークを引き起こします。

RAIIを考えてください:リソース割り当ては初期化です。コンストラクターで、メモリブロックを割り当てます。デストラクタで削除します。その後ReadFile、ブロックの割り当てについて心配する必要はありません。

または、さらに良いことに、@ PiotrNyczが言うように実行し、ポインターを配列に変更します。動的割り当ての必要はありません。

于 2012-10-20T23:54:27.243 に答える