智能指針和前置聲明之間的小問題

對比Go等其餘語言的工程,C++工程讓人痛苦的一件事情就是當工程稍微龐大一點,編譯時間就蹭蹭蹭往上爬。通常來講看過Effective C++這本書或者其餘相似書籍的人都知道要解決編譯時長的問題,就要解決好和頭文件之間的依賴關係。因此在任何須要的時候要首先考慮使用前置聲明而不是之間include頭文件。也就是說,在定義類的時候成員變量若是是自定義類型,能夠考慮將其聲明爲指針類型或者是配合智能指針。函數傳參時也是同樣,使用指針或者引用。app

對於一個C工程來講,由於沒有智能指針和引用的概念,因此都是直接使用指針配合前置聲明。用起來駕輕就熟。ide

可是C++工程裏,有時候爲了方便和省心,更多時候指針類型的成員變量會使用智能指針包一下。這個時候有可能會出現編譯通不過的狀況:函數

MSVC:this

error C2338: can't delete an incomplete type
warning C4150: deletion of pointer to incomplete type 'base';spa

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;code

看到這裏,仍是要感謝下clang的輸出,比較清楚地把問題的本質緣由找出來了。可是等等,我哪裏調用了智能指針的析構函數?對象

稍微有點警覺的狀況下,你應該反應過來是默認的析構函數在作析構智能指針這事情。blog

咱們先來作一個嘗試,把默認的析構函數顯示寫出來,而後按習慣把析構函數的定義放到cpp文件裏。這時你會發現,編譯經過而且能正常運行。ci

問題來了,爲何顯示聲明析構函數並將其定義挪到cpp裏,這個問題就解決了呢?

仍是來一段標準裏的話吧:

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.

因此這個隱式的inline析構函數在調用智能指針的析構函數析構管理的指針對象時,須要知道該對象的大小。而此時只能看到前置聲明而沒法看到定義也就無從知道大小,只能GG了。

 

1 #pragma once
2 
3 struct base
4 {
5   int x;
6 };
base.h
 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 };
test.h
 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 }
test.cpp
1 #include "test.h"
2 
3 int main()
4 {
5   test t;
6   t.print_base();
7 
8   return 0;
9 }
main.cpp
相關文章
相關標籤/搜索