簡體   English   中英

如何顯式調用名稱空間限定的析構函數?

[英]How to explicitly call a namespace-qualified destructor?

我很驚訝以下簡單代碼無法編譯(使用gcc,版本4.8.1)

#include <string>
void test()
{
  std::string* p = new std::string("Destruct me");
  p->std::~string();
}

它說:錯誤:'〜'之前的范圍'std'不是類名。 然而,閱讀標准,我會說語法說它應該是“ postfix-expresssion - > pseudo-constructor-name ”,其中偽構造函數名稱可以是“ nested-name-specifier ~ type-name ”形式,和nested-name-specifier可以是“ identifier ::”。

離開“std ::”會引起一個抱怨,即在左邊的paren之前預計有一個類名,並且在傾向之后將它放在“::”之前預期類名的投訴之后。 經過一番嘗試后我發現編寫時會編譯p->std::string::~string(); (但是當寫一個p->std::string::~std::string();而不是)。 但是使用自己的類型名稱來限定析構函數並不是一個中立的操作; 我從標准的12.4:13中的示例中收集(但奇怪的是不是來自規范性文本),這會強制調用精確靜態(基類)類的析構函數,而不是作為(最大派生的)虛函數指向的實際對象的類型。 這沒有區別,但在相似的情況下它會; 為什么語法會強制使用靜態類型?

但是,使用clang而不是gcc,即使提到的變體也會出現語法錯誤。 如果你在閱讀錯誤消息時有這種幽默的心情,那么clang的錯誤消息會更有趣:對於p->std::string::~string(); 它給出了“預期'〜'之后的類名稱來命名析構函數”(並且它確實如此;人們想知道哪種類名稱如果以波浪號為前綴不會命名析構函數),並且對於我的初始試驗p->std::~string() 〜string p->std::~string()它反駁“限定成員訪問是指名稱空間'std'中的成員”(再次想知道這有什么問題;實際上被調用的析構函數存在於命名空間'std'中)。 我已經嘗試了所有8個合理的組合(在代字號之前的std ::和/或string ::和/或之后的/或std ::)並且它們都沒有用clang編譯。

即使使用clang,我也可以using std::string;進行編譯using std::string; 但我發現很奇怪的是,在標准中我沒有發現這樣的聲明在這種情況下是必要的。事實上,我找不到解決調用命名空間限定類的析構函數的問題。 。 我錯過了一些明顯的東西嗎

作為最后一點,我想補充說,在調用析構函數時,根本不需要使用命名空間限定。 由於這是一個來自一個指定良好的對象(這里是*p )的成員訪問,不應該依賴於參數的查找使顯式限定命名空間不必要嗎?

在標准中,在:

§3.4.5/ 3

如果unqualified-id是~type-name,則在整個postfix-expression的上下文中查找type-name。

因此,似乎應該在std:: namespace的上下文中查找~string

事實上,考慮到相應的自制版本在GCC和Clang上的工作原理如下:

namespace STD {
class STRING {};
}

int main() {
    STD::STRING* a = new STD::STRING();
    a->~STRING();
}

使用gng ++進行clang ++ Live演示的現場演示

我會繼續說這很可能是一個錯誤。


顯然,如果你調用std::string真的是std::basic_string<char>

a->~basic_string();

使用gng ++進行clang ++ Live演示的現場演示

然后一切都編好了。

考慮到以下示例(取自標准),我仍然認為這是一個bug,它表明typedef應該也可以工作:

struct B {
    virtual ~B() { }
};

struct D : B {
    ~D() { } 
};

D D_object;

typedef B B_alias;

B* B_ptr = &D_object;

void f() {
D_object.B::~B();
    B_ptr->~B();
    B_ptr->~B_alias();
    B_ptr->B_alias::~B();
    B_ptr->B_alias::~B_alias();
}

這一概念與§3.4.5/ 3一起應保證:

p->~string();

應該管用。

2019更新:從C ++ 17開始,您可以使用std::destroy_at ,如下所示:

std::destroy_at(p);

它更簡單,遵循現代C ++中不使用“原始構造”(例如new / delete表達式)的原則。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM