2013-07-19 67 views
22

我正在閱讀的STL代碼可能是舊的......但問題更多地與C++模板語法有關。C++ std :: destroy(T *指針)

的問題圍繞着這個STL模板函數:

template<class T> std::destroy(T *p) { 
    p->~T(); 
} 

我似乎無法找到的std ::破壞(T *)功能專業化。所以在我看來,模板函數將爲「int」類型實例化相同的值,並調用「int」的析構函數。爲了表達我的觀點,我創建了模擬std :: destroy的示例代碼。我稱之爲my_destroy,例如。

#include <iostream> 
#include <stdio.h> 
using namespace std; 

template <class T> 
void my_destroy(T * pointer) { 
    pointer->~T(); 
} 
int main() 
{ 
    int *a; 
    //a->~int();  // !!! This won't compile. 
    my_destroy<int>(a); // !!! This compiles and runs. 
} 

}

令我驚訝的是,此行不會編譯:

a->~int(); 

,但此行編譯:

my_destroy<int>(a); 

我的困惑是,我認爲my_destroy<int>(a)將被實例化爲相當於a->~int();

對於較大的上下文中的問題,當<int>的STL容器擦除元素時,std::destroy()如何工作?

+0

我不知道爲什麼這是downvoted,這是一個合法的問題。 +1 – Rapptz

+4

它被稱爲僞析構函數,並擁有自己的特殊規則。基本上,你只能使用* type-name *,它是一個類/枚舉名或typedef名。 – dyp

+1

這是事實,你不能使用關鍵字來調用析構函數。 'typedef int INT; a->〜INT();'編譯。 – milleniumbug

回答

3

該語言允許這些事物啓用泛型編程。然而,你的'直接'調用不是泛型代碼,因此它失敗了。

另一個這樣的情況下是

template <typename T> void foo() 
{ 
    T instance = T(); // default constructor 
} 

foo<int>(); // will work 

所以,是的:

template <typename T> void foo() 
{ 
    T* instance = new T(); // default constructor 
    delete instance;  
} 

還將爲內置的原始類型的工作,因爲T是在範圍類型名加時賽的模板。

+0

'int instance = int();'雖然工作正常。 –

+0

@MooingDuck嗯。這是因爲'int instance;'和'int instance = int();' - 後一個值會對它進行初始化,而前者會使其未初始化。 – sehe

32

需要注意的是,雖然a->~int();不編譯,這樣做:

typedef int INT; 
int* a; 
a->~INT(); 

從標準:

5.2.4p1點後使用pseudo-destructor-name的。或箭頭 - >運算符代表type-namedecltype-specifier所表示的非類別類型的析構函數。結果只能用作函數調用操作符()的操作數,並且此類調用的結果爲void類型。唯一的影響是在點或箭頭之前評估postfix-expression。

從5.2p1:

pseudo-destructor-name: 
    nested-name-specifier_opt type-name :: ~ type-name 
    nested-name-specifier template simple-template-id :: ~ type-name 
    nested-name-specifier_opt~ type-name 
    ~ decltype-specifier 

最後,7.1.6.2p1:

type-name: 
    class-name 
    enum-name 
    typedef-name 
    simple-template-id 

於是,奇怪的是,int在語法上不一個type-name(這是一個simple-type-specifier),所以你可以」 t電話~int(),但INT是,所以你可以。

+0

+1,在這裏我實際回答 – Rapptz

+0

這個問題,這是我當天的最後一次投票。我學到了東西! – TemplateRex

4

對於類類型(非標量類型),則表達式

pointer->~T(); 

本質上是一個函數調用(一個後綴表達式)。要確定要調用的函數,必須分析pointer->~T部分。 ~T是一個id表達式 IFF T類名稱,標識析構函數。

當然,int不是類名。但是,如果T是命名標量類型的類型名稱,則對該表達式的解析方式不同。整個部分pointer->~T被標識爲特殊的後綴表達式,稱爲僞析構函數名稱。通過以下()該表達式被認爲是僞造析構函數的調用([expr.pseudo]中的規則禁止使用僞析構函數名稱進行任何其他操作,但要調用它)。

int本身不是類型名稱 [dcl.type.simple],但簡單型說明符

類型名稱:

  • 講座名稱
  • enum-name
  • typedef-name
  • 簡單模板id

這就是爲什麼你可以使用typedef倒是intT在你的榜樣(*),但不能直接int。推理已被sehe很好地解釋。

僞析構函數調用的規則在[expr.pseudo]中指定:「唯一的效果是在點或箭頭之前評估後綴表達式

從[temp.param]/3

(*): 「A 類型參數其標識符不遵循省略號限定其標識符是一個的typedef名 [...]」

+0

+1優秀背景。我只是把它命名爲我所看到的。也許我太過於務實,想回想一下這個標準,但這肯定是有用的 – sehe