2012-11-13 38 views
2

我已經讀過,不能存儲std::auto_ptrstd::vectorboost::ptr_vector可以用來代替。我已經能夠這樣做了,但我不知道如何使用ptr_vector,當我不想存儲指針時,而是一個結構體,它有一個指針成員。結構域上的智能指針

在這個例子中,我想打開一些文件並將關聯的ofstream對象與一些額外的數據一起存儲,供以後使用。我想用智能指針替換struct datafile字段。由於vector<data> v應該是所有者,我認爲shared_ptr可以工作,但不合適。

我應該用什麼替換裸指針file

#include <iostream> 
#include <fstream> 
#include <vector> 

struct data { 
    std::string filename; 
    std::ofstream* file; 

    data(const std::string filename, std::ofstream* file) 
    : filename(filename), file(file) 
    { 
    } 
}; 

std::vector<data> open_files() 
{ 
    std::vector<data> v; 
    v.push_back(data("foo", new std::ofstream("foo"))); 
    return v; 
} 

int main() 
{ 
    std::vector<data> v = open_files(); 

    /* use the files */ 
    *(v[0].file) << "foo"; 

    delete v[0].file; // either rely on dtor to close(), or call it manually 
} 

更新: 我覺得我已經做了在描述我的問題一個次優的工作,讓我試試另一個例子。此外,我要尋找一個C++ 03的解決方案:

#include <memory> 
#include <vector> 
#include <boost/ptr_container/ptr_vector.hpp> 

struct T { 
    std::auto_ptr<int> a; 
}; 

int main() 
{ 
    // instead of 
    // std::vector<std::auto_ptr<int> > v; 
    // use 
    boost::ptr_vector<int> v; 

    // what to use instead of 
    // std::vector<T> w; 
} 
+0

在data的析構函數中做任何需要清理的操作。由於矢量不包含指針,所以你不得不採取任何行動。如果數據的析構函數是正確的,那麼一切都會自行處理。 – juanchopanza

+0

爲什麼你需要一個(不推薦)的auto_ptr?使用boost :: shared_ptr 這是可複製的。它將由矢量所有並在矢量離開作用域時銷燬。 – hhbilly

+1

'auto_ptr'模擬唯一所有權,而'shared_ptr'具有共享所有權的不同含義。如果我有權訪問C++ 11,我會使用'unique_ptr'。但是使用'share_ptr'可能還是比我的版本更好。 –

回答

1

關於你的數據類,我建議使用std::unique_ptr<std::ofstream>。這不是爲了避免意外內存泄漏,因爲您正在刪除構造函數中的指針,而是將其作爲使所有權顯式爲。你的代碼的用戶必須知道什麼data與它發生在構造函數中的指針做:

std::ofstream ofs; 
{ 
    data d1("crash", &ofs); 
} // error! d1 will attempt to delete stack allocated object 

std::ofstream* pOfs = new std::ofstream(....); 
data d2("crash again", pOfs); 
delete pOFs; // user thinks data makes a deep copy 

然而,隨着unique_ptr的打算是明確的,所以這是很難犯錯誤:

data d3("OK", std::unique_ptr<std::ofstream>(new std::ofstream(....))); 

std::unique_ptr<std::ofstream> pOfs2(new std::ofstream(....)); 
data d4("OK", pOfs2); // safe, pOfs's contents have been safely moved 

// we can check pOfs2 after the move 
if (pOfs2) { /* */ } 
+0

謝謝。你也有C++ 98的建議嗎? –

+0

@MichaWiedenmann不幸的是,沒有一個完全令人滿意的選擇,但是你可以使用'std :: auto_ptr'。你必須保持私密並避免複製。你應該確保你[理解陷阱](http://www.gotw.ca/publications/using_auto_ptr_effectively.htm) – juanchopanza

+0

因爲我打算把封閉類放入一個'vector',(如果'unique_ptr'不是可用)我更喜歡'shared_ptr',儘管它有不同的語義。 –

0

可以在析構函數刪除指針:

struct data 
{ 
    std::string filename; 
    std::ofstream* file; 

    data(const std::string filename, std::ofstream* file) 
    : filename(filename), file(file) 
    { 
    } 
    ~data() 
    { 
    delete file; 
    } 
}; 

或者使用std::unique_ptr來包裝指針,但它在你的情況是不必要的。

0

您不需要擁有ofstream *作爲成員。

#include <iostream> 
#include <fstream> 
#include <vector> 

struct data { 
    std::string filename; 
    data(const std::string filename) : filename(filename) 
    {} 
}; 

std::vector<data> open_files() 
{ 
    std::vector<data> v; 
    v.push_back(data("foo")); 
    return v; 
} 

如果要追加到該文件,指定的應用程序文件模式。

void print_files(const std::vector<data>& v) 
{ 
    for(std::vector<data>::const_iterator it = v.begin(); it != v.end(); ++it) 
    { 
     std::ofstream os(it->filename, std::ostream::app); 
     os << "bar"; 
    } 
} 

int main() 
{ 
    std::vector<data> v = open_files(); 

    print_files(v); 
} 
+0

我將多次寫入不同的文件,並因此提前打開所有文件。 –