调用类型嵌套在类内部的对象析构函数



假设一个class包含一个由嵌套的using定义的类型,该类型的析构函数需要显式调用。是否需要使用using来创建不包括命名空间分隔符(::)的本地类型?

在这个人为的例子中,我想调用A::WeakPtr的析构函数,比如:

wp->~A::WeakPtr();

而不是像:

using AWeakPtr = A::WeakPtr;
wp->~AWeakPtr()

这可行吗?下面是一个完整的例子。

#include <cstdlib>
#include <iostream>
#include <memory>
struct A : std::enable_shared_from_this<A> {
using SharedPtr = std::shared_ptr<A>;
using WeakPtr = std::weak_ptr<A>;
A()  { std::cout << __PRETTY_FUNCTION__ << "n"; }
~A() { std::cout << __PRETTY_FUNCTION__ << "n"; }
};
int
main() {
{
std::unique_ptr<A::WeakPtr, void(*)(void*)>
uwp(static_cast<A::WeakPtr*>(std::malloc(sizeof(A::WeakPtr))), std::free);
A::WeakPtr* wp = uwp.get();
{
auto sp = std::make_shared<A>();
new(wp) A::WeakPtr(sp);
if (wp->lock())
std::cout << "Lockedn";
else
std::cout << "Unlockedn";
}
if (wp->lock())
std::cerr << "EUNPOSSIBLEn";
else
std::cout << "Unable to obtain lockn";
// Need the following 'using' statement because the following is invalid syntax:
// wp->~A::WeakPtr();
using AWeakPtr = A::WeakPtr;
wp->~AWeakPtr();
// Is there a way to call A::WeakPtr without the using statement?
}
std::cout << "memory held by uwp has been free(3)'edn";
}

似乎应该有一种方法来击败::名称空间分隔符,在其中的某个地方散布一个typename,但看起来这是不可能的。显然,如果不可能的话,这不是世界末日,但我的古玩正在战胜我。


更新

正如@DanielFrey和@DyP的精彩回答所建议的那样,正确的语法确实是

wp->A::WeakPtr::~WeakPtr();

但这不起作用,并且是clang++中的一个bug(#12350)(截至2013-09-28)。

你在找吗

wp->A::WeakPtr::~WeakPtr();

此处使用限定id的析构函数调用必须包含:

后缀表达式->嵌套名称说明符~类名()

这里的后缀表达式wp->之后的部分形成单个限定id(没有parens)。

从语法上讲,以下也是可能的:

后缀表达式->嵌套名称说明符~decltype说明符()

然而,第二种形式在[expr.prim.general]/9:中被明确禁止

形式~ decltype-specifier也表示析构函数,但它不应用作限定id中的非限定id。

第一种形式中的类名也可以是typedef名称[class.name]/5:

命名类类型的typedef-name(7.1.3),或其cv限定版本,也是类名

对于在~之后查找此类名,在[basic.lookup.qual]/5:中有一个特殊的名称查找规则

类似地,在形式的合格id中:
 nbsp nbsp嵌套名称说明符opt类名:: ~类名称与第一个相同的范围中查找第二个类别名称

这意味着应该找到A::WeakPtr :: ~WeakPtr中的第二个WeakPtr。它是一个命名类的typedef名称,因此是一个类名。它在A的范围中查找。gcc遵循这个规则,clang++3.4没有。

因此,Daniel Frey建议的wp->A::WeakPtr :: ~WeakPtr();(以及我的第一个已删除的评论/猜测)应该有效。


替代方法:

  1. 使用辅助函数:

    template<class T>
    void destroy(T& t)
    { t.~T(); }
    
  2. 使用decltype说明符w/o限定id。这是一个棘手的问题,因为decltype(*wp)的类型是A::WeakPtr&,而*wp产生一个左值。然而,我们可以将表达式转换为prvalue以摆脱引用:

    wp->~decltype((A::WeakPtr)*wp)();
    // alternatively, w/o explicitly mentioning the type:
    wp->~decltype((std::remove_pointer<decltype(wp)>::type)*wp)();
    // simpler, using a helper function again:
    template<class T>  T helper(T const&);
    wp->~decltype(helper(*wp))();
    

生产:

从函数调用[expr.post]/1:开始

后缀表达式(表达式列表opt)

此处的后缀表达式通过:生成

后缀表达式-> templateoptid表达式

后缀表达式此处映射到wp(在wp->~something()中)。

id表达式包含析构函数"name"[expr.prim.general]:

id表达式:
 nbsp nbsp不合格id
 nbsp 合格id

我们确实需要一个合格的id,所以[expr.prim.general]/8:

合格id:
nbsp nbsp 嵌套名称说明符template nbsp ::标识符
nbsp nbsp ::运算符函数id
nbsp nbsp ::文字运算符id
nbsp nbsp ::模板id

只有第一个感兴趣,所以我们看不合格的ids:

不合格id:
nbsp nbsp 标识符
 nbsp 运算符函数id
nbsp nbsp 转换函数id
nbsp nbsp 文字运算符id
nbsp nbsp ~类名
nbsp nbsp ~decltype说明符
nbsp nbsp 模板id

其中具有~的两个可以用于调用析构函数。

相关内容

  • 没有找到相关文章

最新更新