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...