2012-02-07 16 views
1

私はオブジェクトをストリームで初期化する必要がある(C++)ライブラリを使用しています。ライブラリを備えたサンプルコードは、このコードを使用する:while(!is_eof)の回避

// Declare the input stream 
HfstInputStream *in = NULL; 

try 
{ 
    // This sets up the special stream object for the later object (see below) 
    in = new HfstInputStream("pathToFile.hfsto"); 
} 
// catch errors... 
// {omitted} 

// Initialize the object 
while (not in->is_eof()) { 
    if (in->is_bad()) 
    { 
     std::cerr << "ERROR: Stream cannot be read." << std::endl; 
     exit(1); 
    } 
    // Here we initialize the object using the stream 
    HfstTransducer t(*in); 
} 

私の問題は、このオブジェクトが原因スコープのwhileループの外で使用することができないことです。私はそれをストリームで宣言しなければなりません(私が知る限り)。それを宣言してループ内のストリームで初期化することはできません。

私の質問は(1)間違っていますか?どういうわけか実際にループ外に宣言できますか? (2)これを行う別の(より良い)方法は、ループを完全に回避する方法です。たとえば、try/catchを使用して例外をキャッチするとします。

私はC++には新しく、ベストプラクティスを見つけようとしていますので、何が何であるか教えてください。ありがとう。

また、このオブジェクトの永続バージョンを使用するクラスを作成しようとしていますので、それらを使用する必要があるたびにこれらのオブジェクトを常に作成/破棄する必要はありません。

PS:here's a link to the documentation for the object if it is relevant

は編集:私はループの外で変数を宣言しようとし、それを初期化した場合、私はエラー

HfstTransducer t; 
while (not in->is_eof()) { 
    t(*in); 
} 
// ERROR: main.cpp:47:0 main.cpp:47: error: no match for call to '(hfst::HfstTransducer) (hfst::HfstInputStream&)' 

を取得し、私は間違ってそれを初期化しようとしていますか?

+0

'HfstTransducer t(* in);'はループスコープにあります。しかし、 'HfstInputStream * in'はループの外でそれにアクセスして別の' HfstTransducer'オブジェクトを初期化するか 'HfstInputStream'ポインタを使うだけです。もちろん' HfstTransducer'コンストラクタには移動セマンティクスがあり、 HfstInputStream * in'である。 – lapk

+1

ループ外のt(HfstTranducerタイプのオブジェクト)にアクセスできないという問題はありますか? もしそうなら、それをヒープ上のループの外に宣言し、new演算子を使ってループ内で初期化することができます。 それ以外の場合は、私はあなたの問題を誤解しています。P – Lefteris

+0

申し訳ありませんが、私は明確ではない場合。私は、新しいHfstTransducerオブジェクトを毎回構築するのではなく、HfstTransducerオブジェクトをループの外側に保ち、HfstTransducerを初期化した後にストリームを忘れてしまいたいということを意味しました。それが可能であれば、私の目標です。 – dougalg

答えて

2

あなたが必要なものを達成するために、あなたがそのような中にスコープの外で宣言されたオブジェクトへのポインタを持っている必要があります:

//Declare the pointer to the object outside the while score. This way it will be available to you even outside of the while 
HfstTransducer* t = 0; 
// Initialize the object 
while (not in->is_eof()) { 
    if (in->is_bad()) 
    { 
     std::cerr << "ERROR: Stream cannot be read." << std::endl; 
     exit(1); 
    } 
    // Here we initialize the object using the stream only if it's not already been initialized before 
    // thanks to Necrolis for the observation 
    if(t == 0) 
     t = new HfstTransducer(*in); 
} 

これは、ヒープにHfstTransducer型のオブジェクトを宣言し、初期化します。

delete t; 

EDIT::通常のオブジェクト対ポインタについてのあなたの一般的な質問に答えるために:これは、あなたが明示的に呼び出すことによって、それを呼び出すために持っていることをあなたはスコープを離れた後、デストラクタが独自に呼び出されないことを意味しますが、

これはC/C++の非常に重要な部分です。 これをよりよく説明する記事はhereです。

私が行うことで、いくつかの言葉でそれを説明した場合:

HfstTransducer t; 

をあなたはその型のオブジェクトを宣言し、スタックにそれを入れています。その寿命はスコープの終わりまで続く。スコープが終了するとすぐにそのデストラクタが呼び出されるため、スコープの外にアクセスすることはできません。

HfstTransducer*t = new HfstTransducer(); 

一方

はHfstTransducer型のオブジェクトとしてTを初期化し、ヒープの中に置きます。ヒープは上記の記事を参照してくださいが、基本的にオペレーティングシステムによってプログラムに割り当てられたメモリです。 C++では、演算子newを使用してヒープ内のメモリを求め、オペレータで解放することができます。Cでは、のfree()malloc()関数で同じ結果を得ます。

したがって、デストラクタを明示的に呼び出さない限り、ヒープ内の何かがプログラムの全期間にわたって生きています。この例では、delete tを呼び出して実行できます。

このようにしなければ、すべてのC/C++プログラマが直面しなければならないこと、いわゆるメモリリークが発生します。基本的にあなたが思っていたのは無料ですが、削除/忘れたからではありません。

+0

を参照してください私はわずか数秒前に自分自身を見つけましたが、あなたの答えは必要な詳細を追加しました。役に立つと徹底的に答えてくれてありがとう! – dougalg

+0

また、2行目のポインタを通常のオブジェクトと宣言することとの違いは何ですか? – dougalg

+2

あなたは 't'がループ毎に作成されていないことを確認する必要があります(' t'は 'NULL'に初期化されなければなりません)。 – Necrolis