我正在用C 創建一個庫,我想隨時釋放一些物件。使用原始指標,我無法通知用戶該指標不再有效;使用shared_ptr,如果用戶有自己的shared_ptr,我也無法釋放該物件。所以我決定撰寫我自己的智能指標(ish)類。我的目標是創建一個計算參考的類,并在參考計數達到0時釋放記憶體,這與shared_ptr類似,但是它有一個destroy方法,可以釋放記憶體。同時,用戶可以詢問它的記憶體是否仍然有效(或被釋放)。
pointer_wrapper類包含原始指標和參考計數。正如我之前所說的,如果參考計數達到0或者用戶呼叫destroy方法,它將釋放原始指標。
template< class T> class pointer_wrapper {
private:
T* raw_pointer。
int32_t reference_count = 1;
public:
pointer_wrapper(T* const raw_pointer) 。raw_pointer(raw_pointer) { }
T* get_raw_pointer() const{ return raw_pointer; }
void increase_reference_count() { reference_count ; }
void decrease_reference_count() {
reference_count--。
if( reference_count == 0) {
delete this;
}
}
int32_t get_reference_count() const { return reference_count。}
void destroy(){
if(raw_pointer != nullptr) {
delete raw_pointer;
raw_pointer = nullptr;
}
}
~pointer_wrapper() { destroy(); }; ; ; destroy()
};
但是pointer_wrapper類只是供內部使用,庫的用戶將總是得到一個ptr實體。用戶可以復制ptr物件,但是所有復制的ptr物件的pw變數將指向同一個pointer_wrapper。這樣,如果我呼叫其中一個ptr物件的destroy方法,所有其他ptr物件的is_valid方法將回傳false。因此,如果庫釋放了一個物件,用戶將知道這一點,如果她/他在使用前呼叫is_valid方法。
template< class T> class ptr {
private:
pointer_wrapper<T>* pw;
public:
ptr(T* const raw_pointer) { pw = new pointer_wrapper< T> (raw_pointer); }
ptr(pointer_wrapper<T>* const pw) 。pw(pw) { pw->increase_reference_count(); }
ptr(const ptr<T> & other_ptr) {
pw = other_ptr.pw;
pw->increase_reference_count()。
}
ptr<T>& operator=(const ptr< T>& other_ptr) {
pw->decrease_reference_count()。
pw = other_ptr.pw。
pw->increase_reference_count()。
return *this。
}
T* operator->() const { return pw-> get_raw_pointer(); }
int32_t get_reference_count() const { return pw-> get_reference_count(); }
bool is_valid() const{ return pw-> get_raw_pointer()! = nullptr; }
//問題可能出在這里。
template<class X> ptr< X> convert() const{ return ptr< X>(reinterpret_cast<pointer_wrapper<X>*>(pw)); }
void destroy() { pw->destroy(); }
~ptr() { pw->decrease_reference_count(); }; ~ptr()
};
一般的模式是,我有一個匯出的類似介面的類,只有純虛擬方法,我有一個實作類(沒有匯出,隱藏在dll中),繼承自類似介面類。
static ptr<window_system> create(){ return ptr< window_system>(new wm_glfw_window_system()); }
這樣做很好,直到我試圖通過呼叫convert方法來鑄造它。如果我在轉換后的ptr物件上呼叫一個方法,我會得到一個類似這樣的錯誤:
Exception thrown at 0x000000000000 in example_1.exe: 0xC0000005: 執行位置0x000000000000.的訪問違規。
ptr< window_system> (new wm_glfw_window_system())-> create_window(. ...); //作業正常。
ptr<wm_glfw_window_system>(new wm_glfw_window_system())->create_window(。 ...); //作業正常。
ptr<wm_glfw_window_system>(new wm_glfw_window_system() )。 convert<window_system>()->create_window(...); /錯誤。
ptr<window_system>(new wm_glfw_window_system()) 。 convert<wm_glfw_window_system>()->create_window(..); // error
所以我想我對那個convert方法和reinterpret_cast有一些問題。但是如果我是正確的,我不能使用其他的轉換,因為ptr<window_system>類和ptr<wm_glfw_window_system>沒有關系,盡管window_system和wm_glfw_window_system類是相關的。
所以我的問題是:
- 是否有更好的方法來解決這個問題?
- 是否有更好的方法來歸檔我的目標(例如,一個具有適當指標型別的庫)?
- 我的類是否有意義?
- 我如何寫我的
convert方法來正常作業(它必須支持下轉換)?
uj5u.com熱心網友回復:
不要重復投遞。
用一個指向物件的指標和一個參考計數幫助器來替換指向指標包裝器的單一指標。
在指向物件的指標中支持靜態、隱式和動態的投擲,保持相同的參考計數器。
uj5u.com熱心網友回復:
用
shared_ptr我不能釋放物件,如果用戶有她/他自己的shared_ptr到它。 是否有一個更好的方法來歸檔我的目標(例如,一個具有適當指標型別的庫)?
看來你只需要把std::weak_ptr交給你的用戶。
如果你不希望他們轉換和存盤std::shared_ptr,你可能會把它包裝在一個類中,比如:
template <class T> class
pointer_wrapper {
private:
std::weak_ptr<T> 指標。
public:
pointer_wrapper(std::weak_ptr<T> pointer)。pointer(pointer) {}.
template <typename F>
bool do_job(F f) {
if (auto p = pointer.lock() ) {
f(*p)。
return true。
}
return false;
}
void destroy(){
do_job([](auto& v){
//通知你的庫洗掉shared_ptr.。
v.release_itself()。
});
}
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/332993.html
標籤:
