2012-02-07 78 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 2012-02-07 07:50:44

+1

您的問題是您無法在循環之外訪問t(它是HfstTranducer類型的對象)? 如果是這樣,那麼你可以在堆的循環之外聲明它,並使用新運算符在循環內初始化它。 如果不是那麼我只是誤解了你的問題:P – Lefteris 2012-02-07 08:05:11

+0

對不起,如果我不清楚。我的意思是我希望將HfstTransducer對象放在循環外部,並在HfstTransducer初始化後忘記流,而不是每次都創建一個新的HfstTransducer對象。如果這是可能的,這是我的目標。 – dougalg 2012-02-07 08:05:49

回答

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; 

編輯:要回答有關指針與正常對象一般問題:

這是C/C++的一個非常重要的部分。 一篇文章可以更好的解釋這個問題here

如果我做解釋這幾句話:

HfstTransducer t; 

你宣稱類型的對象,並把它在堆棧中。它的生命週期只能持續到示波器的結束。您無法訪問它的範圍,因爲它的析構函數將在範圍結束後立即被調用。

在另一方面

HfstTransducer*t = new HfstTransducer(); 

初始化噸作爲HfstTransducer類型的一個對象,並把它在堆中。關於堆是指上面的文章,但它基本上是由操作系統分配給您的程序的內存。在C++中,你需要與運營商堆中的內存並將其與刪除運算符一起釋放。在C中,您可以通過免費()malloc()函數實現相同功能。

因此,除非明確調用析構函數,否則堆中的某些內容在整個程序期間都是活着的。正如你可以通過調用刪除t;

不這樣做會導致所有C/C++程序員必須面對的問題,即所謂的內存泄漏。基本上你認爲是免費的內存,但並不是因爲你忘記刪除/釋放它。

+0

我發現自己在幾秒鐘之前就已經發現了,但是您的答案還添加了我需要的詳細信息(如致電刪除)。非常感謝你的幫助和徹底的答案! – dougalg 2012-02-07 08:21:10

+0

此外,聲明第二行中的指針與常規對象之間有什麼區別? – dougalg 2012-02-07 08:22:22

+2

你需要檢查't'還沒有被創建每個循環迭代(這意味着't'必須被初始化爲'NULL'),否則你會泄漏內存。 – Necrolis 2012-02-07 08:23:28