模板化上下文中的显式析构函数

时间:2011-07-27 14:05:51

标签: c++ templates destructor

我想在模板化的上下文中明确销毁vector。以下适用于我(GNU C ++ 4.3,4.4和Clang ++ 1.1):

template <typename T>
void destroy_vector_owner(VectorOwner<T> *obj)
{
    obj->v.~vector();
    // further cleanup by Python API functions omitted
}

虽然在Mac OS X v10.5 g++i686-apple-darwin10-gcc-4.2.1)上失败但

expected class-name before ‘(’ token

如果我将其更改为

obj->v.~vector<T>();

代码无法用G ++编译,但Clang仍然可以处理它。哪个是正确的成语?在这方面是否已知这些编译器中的任何一个被打破?

更新VectorOwner的定义是

template <typename T>
struct VectorOwner {
  PyObject_HEAD
  std::vector<T> v;
};

这是一个必须保持std::vector活着的Python对象。我承认构造稍微有点危险,但我需要紧凑的存储,摊销O(1)push_back并且能够使用swap成员窃取另一个向量的内容。

3 个答案:

答案 0 :(得分:3)

从n3290,3.4.5类成员访问[basic.lookup.classref]

  

3如果unqualified-id为~type-name,则查找type-name   整个后缀表达式的上下文。如果是T型   对象表达式是类C类型,也可以查看类型名称   在C类的范围内。至少有一个查找应该找到一个   引用(可能是cv-qualified)T [...]

的名称

以下是一个示例(作为非规范性说明),其中包含以下代码片段:

a->~A(); // OK: lookup in *a finds the injected-class-name

特别是对于template<typename T, typename Allocator> class vector;vector是注入类名。因此,我相信

obj->v.~vector();

是对的。

(目前我对~vector<T> 没什么可说的。

答案 1 :(得分:3)

我的第一个答案实际上是错误的,litb指出了我正确的方向。正确的答案是 这两种语法都是正确的:


析构函数调用语法。

12.4 Destructors

中描述了显式析构函数调用的语法
12  In an explicit destructor call, the destructor name appears
    as a ˜ followed by a type-name that names the destructor’s 
    class type. The invocation of a destructor is subject to the
    usual rules for member functions (9.3) [...]

type-name位于7.1.5.2 Simple type specifiers

type-name:
    class-name
    enum-name
    typedef-name
class-name中描述了

9. Classes

class-name:
    identifier
    template-id

因此,析构函数调用简化为以下

之一
foo.~typedef-name ()
foo.~identifier   ()
foo.~template-id  ()

我们这里既没有typedef-name,也没有简单的标识符,所以只留下foo.~template-id() 对我们来说。


编译器对使用模板参数进行析构函数调用的假设。

我们也在14. Templates

中找到了
3 After name lookup (3.4) finds that a name is a template-name,
  if this name is followed by a <, the < is always taken as the
  beginning of a template-argument-list and never as a name
  followed by the less-than operator.

因此,编译器必须在您的示例中假设<是开头 模板参数列表。

另外,如果你的析构函数是模板(...),那么

4   When the name of a member template specialization appears 
    after . or -> in a postfix-expression, or after nested-name-specifier
    in a qualified-id, and the postfix-expression or qualified-id explicitly
    depends on a template-parameter (14.6.2), the member template name must
    be prefixed by the keyword template. Otherwise the name is assumed to 
    name a non-template.

因为你没有为你的析构函数调用f.~foo<int>添加模板前缀,即 像f.template ~foo<int>一样,编译器必须假设你的析构函数 不是模板。

原路返回。

此外,

6   A template-id that names a class template specialization
    is a class-name (clause 9).

因此~foo<int>为您的模板专精foo<int>命名,因此是class-nameclass-name由语法规则type-name构成,~后跟typenamefoo<int> f; f.~foo<int>(); // valid 析构函数调用。因此

f.~foo(); // valid

没有模板参数的析构函数调用。

但也

3.4.5 Class member access

因为3 If the unqualified-id is ˜type-name, and the type of the object expression is of a class type C (or of pointer to a class type C), the type-name is looked up in the context of the entire postfix-expression and in the scope of class C. [...]

f.~foo();

因此在foof.内查找foo<int>foo范围内的,{/ 1}}范围内的 仅使用5 An explicit destructor call (12.4) for an object that has a type that is a class template specialization may explicitly specify the template-arguments. [Example: template<class T> struct A { ˜A(); }; void f(A<int>* p, A<int>* q) { p->A<int>::˜A(); // OK: destructor call q->A<int>::˜A<int>(); // OK: destructor call } —end example] 来引用它。


该标准实际上是明确的,d。哦。

最后,14.3包含了一对一的权限:

{{1}}

答案 2 :(得分:0)

您可以尝试以下语法在gcc中使用:

obj->v.template ~vector<T>();

Demo