1

このコードのどこが間違っていて、それを修正する方法は?

int _tmain(int argc, _TCHAR* argv[])
{
std::ostream * o = &std::cout;
char text[4096];
char *file = "D://test.txt";

if ( file != NULL ) 
{
  strcpy ( text, file );
  strcat ( text, ".log" );
  o = & std::ofstream ( text );
}
*o << "test"; //Exception
return 0;
}
4

6 に答える 6

4
o = & std::ofstream ( text );

右側の式は一時を作成し、式の最後で破棄される一時のアドレスを取得します。その後、使用oすると未定義の動作が呼び出されます。

あなたはこれをしているはずです:

{
   //...
   o = new std::ofstream ( text );
   if ( *o )
        throw std::exception("couldn't open the file");
}
//...

if  ( o != &std::cout )
   delete o; //must do this!
于 2011-08-05T16:32:29.477 に答える
2

コンパイルされるべきではありません。式std::ofstream( text )は右辺値 (一時) であり、C++ では一時のアドレス (演算子) を取得できません&。また、テンポラリの有効期間は完全な式の終わりまでしかないため;、ステートメントの最後に を渡すとすぐに、そのデストラクタが呼び出されます (そして、それが存在するメモリは他の目的に使用される可能性があります)。

名前付きローカル変数を作成するofstreamだけでは、変数の有効期間はそれが宣言されたブロックの最後 (次の ) までしかないため、役に立ちません}std::ofstreamの前にを定義し、 それifを開いてoif に設定する必要があります。

std::ofstream mayOrMayNotBeUsed;
if ( file != NULL ) {
    //  ...
    mayOrMayNotBeUsed.open( text );
    if ( !mayOrMayNotBeUsed.is_open() ) {
        //  Do something intelligent here...
    }
    o = &mayOrMayNotBeUsed;
}
于 2011-08-05T16:38:58.810 に答える
1

これ

o = & std::ofstream ( text );

一時オブジェクトを作成oし、このオブジェクトのアドレスを指し始め、後で(この行の実行直後に)オブジェクトが破棄されます。したがって、未定義の動作(無効なポインタを逆参照する場合)。

解決策-次のように作成しますnew

o = new std::ofstraem( text );

ただし、次の前に、割り当てられたメモリを解放することを忘れないでくださいreturn

*o << "test";

if  ( &std::cout != o  ) // don't forget the check .. as I did at the first time
{
    o->close();  // not absolutely necessary, 
             // as the desctructor will close the file
    delete o;
}
return 0;
于 2011-08-05T16:33:29.650 に答える
1

問題は、このコードにより未定義の動作が発生することです。

o = & std::ofstream ( text );

あなたが書くとき

std::ofstream ( text )

ostreamこれにより、ステートメントの実行が終了するとすぐに有効期間が終了する一時オブジェクトが作成されます。そのアドレスを取得してポインターに割り当てると、ポインターoは、寿命がもうすぐ終わる一時オブジェクトを指すようになります。ステートメントの実行が終了するとすぐに、oは有効期間が終了したオブジェクトを指しているため、そのオブジェクトを使用すると未定義の動作が発生します。したがって、あなたが書くとき

*o << "test";

死んだオブジェクトに対して操作を実行しようとしており、問題が発生しています。

これを修正するには、次のいずれかを行う必要があります

  1. ofstreamを記述して動的に割り当てo = new std::ofstream(text);ます。これにより、オブジェクトの有効期間がステートメントの末尾を超えて延長されるようにオブジェクトが作成されます。または
  2. std::ofstreamの先頭で を宣言して_tmain、その有効期間が関数の残りの部分全体に及ぶようにします。

お役に立てれば!

于 2011-08-05T16:32:18.087 に答える
1

o = & std::ofstream ( text );これにより、アドレスが割り当てられた一時的な ofstream オブジェクトが作成されoますが、オブジェクトは即座に破棄さoれるため、削除されたオブジェクトを指します。これは機能するはずです(静的を使用):

int _tmain(int argc, _TCHAR* argv[])
{
    std::ostream * o = &std::cout;
    char text[4096];
    char *file = "D://test.txt";

    if ( file != NULL ) 
    {
        strcpy ( text, file );
        strcat ( text, ".log" );
        static std::ofstream myofstream( text );
        o = &myofstream;
    }
    *o << "test"; //Exception
    return 0;
}
于 2011-08-05T16:32:43.200 に答える
0

あなたは非常に不健全な方法で C と C++ を混ぜているのではないかと心配しています。

まず、std::stringの代わりに を使用することを心からお勧めしchar*ます。信じてください。問題がはるかに少なくなります。

次に、ポインターに注意する必要があります。注意しないと、「ライブ」オブジェクトをホストしなくなったメモリ内の場所を指す可能性があります。

次のコードを提案します。

void execute(std::ostream& out) {
  out << "test\n";
} // execute

int main(int argc, char* argv[]) {
  if (argc == 1) {
    execute(std::cout);
    return 0;
  }

  std::string filename = argv[1];
  filename += ".log";

  std::ofstream file(filename.c_str());
  execute(file);
  return 0;
}

これは、陥った 2 つの落とし穴を回避する方法を示しています。

  • を使用するstd::stringと、静的なサイズのバッファーを割り当てることが回避されるため、バッファー オーバーフローのリスクが生じます。さらに、操作はとても簡単です。
  • 関数を使用して印刷ロジックを引き上げ、ポインターとそれがもたらす微妙な問題を取り除きます。

std::string現時点では、 and std::fstream(および配偶者) がうまく混ざり合っていないのは残念です。歴史的な欠陥... 私の記憶が正しければ、C++0x で修正されました。

于 2011-08-05T17:47:29.160 に答える