C ++ std :: destroy(T *指针)

时间:2013-07-19 21:23:12

标签: c++ stl

我正在阅读的STL代码可能已经过时了......但问题与C ++模板语法有关。

这个问题围绕着这个stl模板函数:

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

我似乎无法找到std :: destroy(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()如何工作?

3 个答案:

答案 0 :(得分:32)

请注意,虽然a->~int();无法编译,但这样做:

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

来自标准:

5.2.4p1在点后使用pseudo-destructor-name。或箭头 - &gt; operator表示由type-namedecltype-specifier表示的非类类型的析构函数。结果只能用作函数调用operator()的操作数,并且这种调用的结果类型为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),因此您无法调用~int(),但INT是所以你可以。

答案 1 :(得分:4)

对于类类型(非标量类型),表达式

pointer->~T();

本质上是一个函数调用( postfix-expression )。要识别要调用的函数,必须分析部分pointer->~T~T id-expression IFF T类名,用于标识析构函数。

当然,int不是类名。但如果T type-name 命名标量类型,则同一表达式的解析方式不同。整个部分pointer->~T被标识为一个特殊的后缀表达式,称为伪析构函数名称。使用以下()表达式被认为是伪析构函数的调用([expr.pseudo]中的规则禁止使用伪析构函数名称执行任何其他操作但调用它)。

int本身不是类型名称 [dcl.type.simple],而是简单类型说明符

  

类型名称:

     
      
  • 类名
  •   
  • 枚举名称
  •   
  • 的typedef名
  •   
  • 简单模板id
  •   

这就是为什么你可以使用typedef'd intT作为示例(*),而不是直接使用intsehe已经很好地解释了推理。

伪析构函数调用的规则在[expr.pseudo]中指定:“唯一的效果是在点或箭头之前评估 postfix-expression 。”

来自[temp.param] / 3的

(*):“ type-parameter ,其标识符不遵循省略号,将其标识符定义为 typedef-name [...]“

答案 2 :(得分: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是模板范围内的类型名称。