c 11中std unique ptr需要明確知道型別的析構函式,而shared ptr不需要?

時間 2021-05-08 01:23:52

1樓:土地測量員

詳細講一下std::unique_ptr的部分吧。

std::unique_ptr需要明確知道型別的析構函式

unique_ptr型別是

template<

class T,

class Deleter = std::default_delete

> class unique_ptr;

private:T

*p;Deleter

del;

然後析構的時候就會這樣:

~unique_ptr()

當Deleter是預設的std::default_delete時,del(p)就會delete p,delete會呼叫析構函式。而delete乙個不完整型別的指標是ub。

在典型的實現中都會在delete前通過static_assert(sizeof(T) > 0)做檢查。 sizeof 對 incomplete type求值會直接編譯出錯。

所以,當Deleter非預設時,就不一定需要知道型別的析構函式。比如

// A is incomplete type

class A;

auto Del = (A*) ;

std::unique_ptr ptr;

而對於std::shared_ptr來說

按理說reset的時候需要delete ptr就需要ptr的型別(錯了請指正),而shared_ptr的template type可以是incomplete type(錯誤請指正)。

應該不太正確。。cppreference是這麼描述的:

std::shared_ptr may be used with an incomplete type

T. However, the constructor from a raw pointer (template shared_ptr(Y*)) and the templatevoid reset(Y*) member function may only be called with a pointer to a complete type (note that std::unique_ptr may be constructed from a raw pointer to an incomplete type).

reset的時候需要型別完整。預設構造的時候允許是不完整型別。

2樓:sin1080

在常見實現裡,shared ptr把deleter(包括預設情況下的operator delete)放進control block,相當於做了一次type erasure,把deleter的型別從shared_ptr型別本身裡面擦下去。deleter的型別在control block的具體型別上,shared_ptr本身只持有乙個control block基類的指標,通過虛函式來呼叫deleter。而因為shared_ptr構造的時候要求必須是complete type,control block已經知道怎麼析構了。

世界和平,shared_ptr析構的時候就呼叫個虛函式,具體事情它不管的。

unique_ptr沒有control block,deleter type(包括預設的std::default_delete)直接做在unique_ptr一起了,這就導致unique_ptr的析構函式需要親手析構被管理的型別,因此析構函式必須看到complete type。然而反過來,因為構建的時候只需要儲存下指標,所以unique_ptr構造的時候不需要看到complete type。

這倆正好是反的。

C++標準並沒有規定這些實現細節,但是規定函式簽名和特性的時候,是考慮著比較合理的實現方式來寫標準的,到最後標準落下來之後也差不多只能這麼實現了。

3樓:饒萌

這本質是個量變引起質變的過程。

對shared_ptr來說,除了封裝的raw_ptr外還要儲存ref_cnt和weak_cnt,因此需要額外的儲存空間儲存,gcc使用乙個control block來存訪兩個cnt,shared_ptr中會儲存control block的指標(因此shared ptr是兩個指標的大小)。如果需要使用者自定義的析構函式,可以在構造shared ptr時把析構函式的指標也放入control block,這樣在release的時候會自動呼叫這個函式,因此shared ptr的型別定義中可以不需要知道析構函式的型別。

而unique_ptr的最大不同在於它沒有control block,它只是簡單的封裝了下raw ptr,提供了控制建構函式而已,所以它的size就是乙個指標。如果要像shared ptr那樣也儲存析構函式的指標的話,只能引入control block,並增大object size,這會引起質變。shared ptr之所以沒這個問題是因為它從一開始就質變過了。

4樓:maxint

reset操作是先delete後賦值,如果不是用make_shared或make_unique,物件的記憶體不會涉及allocator。指標能怎麼用,它們就能類似的用,如指標定義時不用指標指向型別的定義。delete abstract type應該沒問題吧,delete(reset/destruction)的時候能abstract type的定義可見。

按 @流光溢彩的說法,如果在初始化時做type erase就更有趣了,需要再看下文件和實現。

5樓:流光溢彩

用raw pointer初始化shared_ptr是,需要complete type,這個時候做type erased,在析構時就不用管type了,而且做到了非virtual 析枸也能正確執行。

sizeof incomplete type,會觸發編譯錯誤。與大於零,沒什麼直接關係,可能為了避免優化吧。

6樓:馮東

delete ptr 並不需要知道 ptr 的具體型別。ptr 指向的 buffer 大小是由 allocator 開闢的空間的 bookkeeping 資料決定的,可以通過 ptr 加固定便宜找到。ptr 的 dtor 可以通過 virtual function pointer 找到。

C 11 中 typedef 和 using 有什麼區別?

碧水溪風 說個真事,同事n年c 開發經驗,c 特別溜。有一次我拿typedef和 define反過來覆過去問他,一分鐘不到他就懵圈了,根本分不清typedef和 define該怎麼用了。 原子筆 using 是C 11用來擴充套件typedef 的,不在typedef上擴充套件是為了盡可能保持C語言...

C 11為什麼引入nullptr?

徐辰 因為C 他爹早就看0這個magic number不爽了,當年沒顧上搞,一直拖到2011年了,再不瘋狂一把C 就沒人用了。 enpeng xu 問題的關鍵是c 不知道怎麼正確做void 到 T 的預設轉換,所以多此一舉的引入了nullptr。某些情況做下c 編譯器不知道怎麼把 void ptr正...

C 11 模板引數推導(Template Argument Deduction)是如何工作的?

electrlife 關於模版推導,借題主地盤,請教下如下情況如何理解?template class MyVector private T aa int main int argc,const char argv 這裡本意是請問 push back 的const 在推導過程是不是會重複const c...