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

肖恩

假设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 << "Locked\n";
      else
        std::cout << "Unlocked\n";
    }

    if (wp->lock())
      std::cerr << "EUNPOSSIBLE\n";
    else
      std::cout << "Unable to obtain lock\n";

    // 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)'ed\n";
}

似乎应该有一种方法可以打败分散在某处::名称空间分隔符typename,但似乎不可能。显然,如果不可能的话,这不是世界末日,但是我的古玩正在使我变得更好。


更新

正如@DanielFrey和@DyP的绝妙答案所暗示的那样,正确的语法确实是

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

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

深的

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

postfix-expression -> 嵌套名称说明符 ~ 类名称 ()

所述后缀表达式这里wp,和之后的部分->形成 合格-ID(W / O的括号)。

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

postfix-expression -> 嵌套名称说明符 ~ decltype-specifier ()

但是,[expr.prim.general] / 9中明确禁止使用第二种形式:

该格式~ decltype-specifier还表示析构函数,但不得qualified-id中用作unqualified -id

一种形式类名也可以是typedef-name [class.name] / 5:

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

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

类似地,采用以下形式限定ID
     nested-name-specifier opt class-name :: ~ class-name,在与第一个相同的作用域中查找
第二个类名

这意味着,第二WeakPtrA::WeakPtr :: ~WeakPtr应该可以找到。这是一个为类命名typedef名称,因此是一个class-name,并在的范围内进行了查找Agcc遵循此规则,而clang ++ 3.4则不这样做。

因此,wp->A::WeakPtr :: ~WeakPtr();建议丹尼尔·弗雷(和我的第一个,删除评论/猜测)应该工作。


替代方法:

  1. 使用辅助功能:

    template<class T>
    void destroy(T& t)
    { t.~T(); }
    
  2. 使用w / oaqualified -iddecltype-specifier这是一个棘手的问题,因为类型,所以会产生一个左值。但是,我们可以将表达式转换为prvalue以摆脱引用:decltype(*wp)A::WeakPtr&*wp

    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开始:

postfix-expression ( 表达式列表opt )

这里的postfix-expression是通过以下方式产生的:

后缀表达式 -> templateopt id表达式

postfix-expression此处映射到wp(中的wp->~something())。

id表达式包含析构函数“名称” [expr.prim.general]:

id-expression:
     不合格ID
     合格ID

我们这里确实需要一个合格的ID,因此[expr.prim.general] / 8:

合格ID:
     嵌套名称说明符 templateopt 不合格ID
     :: 标识符
     :: operator-id
     :: -literal-operator-id
     :: template-id

只有第一个感兴趣,因此我们看一下unqualid-id

不合格ID:
     标识符
     运算符功能ID
     转换功能ID
     文字运算符ID
     ~ 类名
     ~ decltype-specifier
     模板ID

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章