2011-06-17 62 views
3

我有一個很好的資源管理類。具體來說,讓它成爲一個用於管理FILE *的文件類(處理打開和關閉操作)有條件地使用RAII的最佳方式

當存在資源不需要由我管理的情況下,通常的做法是什麼?是別人的責任?

對於ilustrative目的,我現在有這樣的事情:

int main(int argc, char** argv) 
{ 
    File my_file(argv[1]); //I unconditionaly obtain the resource 
    //... 
    return 0; //and unconditionally relinquish with the destructor 
} 

而且要像

int main() 
{ 
    if(argc <= 1){ 
     //use stdin that is already available 
    }else{ 
     //obtain a file from argv[1] 
    } 
    //... 
    if(argc <= 1){ 
     //nothing to do 
    }else{ 
     //close the file we obtained 
    } 
} 

(但不太難看,更健壯,等...)

回答

2

您的RAII類已經保持足夠的狀態來知道何時銷燬它所控制的資源。它也可以包含一個標誌,告訴它資源是否應該被銷燬,或者你可以在計數器上使用一個特殊的值來表明該資源是在類之外被控制的。

然後,您只需要一種方法來控制獲取資源時的狀態。例如,您可以有兩個不同的構造函數,或者構造函數上的參數具有默認值。您可以使用Attach方法來附加現有資源。這完全取決於你。

0

最常見的模式不允許這樣做。但是,您可以允許Standard爲其容器提供定製分配器插件,這將允許這些語義。這是一個簡短的示例 -

class Allocator { 
    File* Allocate(...) { 
     return fopen(...); 
    } 
}; 
class MyStdinAllocator { 
    File* Allocate(...) { 
     return ...; 
    } 
}; 
template<typename MyAllocator = Allocator> class File { 
    File* ptr; 
    Allocator alloc; 
    File(..., const Allocator& allocref) 
    : alloc(allocref) { 
     ptr = alloc.Allocate(...); 
    } 
}; 
2

您可以推送是否使用資源管理類中的資源的邏輯。那麼它就不再有條件了。只要做

int main(int argc, char** argv) 
{ 
    File my_file(argc > 1 ? argv[1]: NULL); //If NULL, File will point to stdin 
    //... 
    return 0; //File's destructor will run, relinquishing resources if necessary. 
} 
6

boost::shared_ptr允許您傳遞一個自定義的析構函數。如果你在包裝外部管理指針,你可以通過一個無操作:

namespace { 
template<typename T> 
void noop_destruct(T *) throw() { } 
} 

template<typename T> 
boost::shared_ptr<T> make_dummy_shared_ptr(T *p) { 
    return boost::shared_ptr<T>(p, noop_destruct); 
} 

現在,當你需要一個真正的RAII對象,使用普通boost::shared_ptr,當你需要一個假的,使用像這樣的適配器 - 它的行爲與普通指針完全一樣。

+0

+1,我在幾個地方用noop析構函數使用共享指針。真的很有用 – totowtwo

+1

如果想避免引用計數開銷,也可以用'unique_ptr'來完成。 – ildjarn

+0

unique_ptr @Ildjarn的缺點是必須將deleter類型指定爲模板參數,因此用於非操作案例的刪除器需要與用於其他案例的刪除器類型相同。 –