智能指針和前置聲明之間的小問題
對(duì)比Go等其他語言的工程,C++工程讓人痛苦的一件事情就是當(dāng)工程稍微龐大一點(diǎn),編譯時(shí)間就蹭蹭蹭往上爬。一般來說看過Effective C++這本書或者其他類似書籍的人都知道要解決編譯時(shí)長(zhǎng)的問題,就要解決好和頭文件之間的依賴關(guān)系。所以在任何必要的時(shí)候要首先考慮使用前置聲明而不是之間include頭文件。也就是說,在定義類的時(shí)候成員變量如果是自定義類型,可以考慮將其聲明為指針類型或者是配合智能指針。函數(shù)傳參時(shí)也是一樣,使用指針或者引用。
對(duì)于一個(gè)C工程來說,因?yàn)闆]有智能指針和引用的概念,所以都是直接使用指針配合前置聲明。用起來得心應(yīng)手。
但是C++工程里,有時(shí)候?yàn)榱朔奖愫褪⌒?,更多時(shí)候指針類型的成員變量會(huì)使用智能指針包一下。這個(gè)時(shí)候有可能會(huì)出現(xiàn)編譯通不過的情況:
MSVC:
error C2338: can't delete an incomplete type
warning C4150: deletion of pointer to incomplete type 'base';Clang:
error : invalid application of 'sizeof' to an incomplete type 'base'
static_assert(0 < sizeof (_Ty),
^~~~~~~~~~~~
note: in instantiation of member function 'std::default_delete<base>::operator()' requested here
this->get_deleter()(get());
^
./main.h(6,8) : note: in instantiation of member function 'std::unique_ptr<base, std::default_delete<base> >::~unique_ptr' requested here
struct test
^
./main.h(5,8) : note: forward declaration of 'base'
struct base;
看到這里,還是要感謝下clang的輸出,比較清楚地把問題的本質(zhì)原因找出來了。但是等等,我哪里調(diào)用了智能指針的析構(gòu)函數(shù)?
稍微有點(diǎn)警覺的情況下,你應(yīng)該反應(yīng)過來是默認(rèn)的析構(gòu)函數(shù)在做析構(gòu)智能指針這事情。
我們先來做一個(gè)嘗試,把默認(rèn)的析構(gòu)函數(shù)顯示寫出來,然后按習(xí)慣把析構(gòu)函數(shù)的定義放到cpp文件里。這時(shí)你會(huì)發(fā)現(xiàn),編譯通過并且能正常運(yùn)行。
問題來了,為什么顯示聲明析構(gòu)函數(shù)并將其定義挪到cpp里,這個(gè)問題就解決了呢?
還是來一段標(biāo)準(zhǔn)里的話吧:
12.4/4
If a class has no user-declared destructor, a destructor is implicitly declared as defaulted(8.4). An implicitly declared destructor is an inline public member of its class.
所以這個(gè)隱式的inline析構(gòu)函數(shù)在調(diào)用智能指針的析構(gòu)函數(shù)析構(gòu)管理的指針對(duì)象時(shí),需要知道該對(duì)象的大小。而此時(shí)只能看到前置聲明而無法看到定義也就無從知道大小,只能GG了。
1 #pragma once 2 3 struct base 4 { 5 int x; 6 };
1 #pragma once 2 3 #include <memory> 4 5 struct base; 6 struct test 7 { 8 std::unique_ptr<base> base_; 9 10 void print_base() const; 11 };
1 #include "main.h" 2 #include "base.h" 3 4 #include <cstdio> 5 6 void 7 test::print_base() const 8 { 9 std::printf("%d\n", base_->x); 10 }
1 #include "test.h" 2 3 int main() 4 { 5 test t; 6 t.print_base(); 7 8 return 0; 9 }
posted on 2017-08-04 11:51 wpcockroach 閱讀(2658) 評(píng)論(0) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)