C++ 模板类显示调用析构函数的行为怎样体现?

我发现在 C++17 中,std::allocator::destroy 被废弃了:

http://zh.cppreference.com/w/...

而替代方案是显示调用析构函数。就此我产生了一个疑问,为了描述清楚,先构造一个类:

template<typename T> class Object {
    T* data_;
public:
    Object() { data_ = (T*) malloc(sizeof(T)); }
    void Construct() { new (data_) T(); }
    void Destory() { data_->~T(); }
    T& operator->() { return *data_; }
    ~Object() { free(data_); }
};

我认为 Object<int>::Destory() 会导致 data_->~int(),而后者自然是不能通过编译的。

但测试发现,Object<int> o 的构造不会产生编译错误(g++ (Ubuntu 4.9.3-13ubuntu2) 4.9.3)。那么:

  1. 这种行为是 C++ 标准的,还是 g++ 特有的?
  2. 应该怎样阐述 data_->~T() 的行为?
阅读 4.8k
1 个回答

感谢 @felix 指教,为了清晰起见,我自答一下:

  1. 这个行为是 C++ 标准的,还是 g++ 特有的?

    这种行为是 C++ 标准的。参考:

    http://zh.cppreference.com/w/...

    之中【内建的成员访问运算符】,第四种用法:

    expr -> pseudo-destructor

    expr 是一个标量类型,pseudo-destructor 为一个 ~ 之后跟着代表与 expr 相同类型的类型名,所构成的函数调用表达式被称为伪析构函数调用。它不接受任何参数,返回 void,且除了对开头的 expr 求值之外不实施任何操作。允许进行伪析构函数调用,使得编写代码而无需了解某个给定类型是否存在析构函数成为可能。

    上面叙述中的类型名(type name)对当前语法来说,可以指 typedef 或者 using(type alias)声明的名字,而不指类型本身。举例说明:

    int main() {
        typedef int Int;
        int* p = new int(10);
        p->~Int(); // ok, do nothing
        // p->~int(); error: expected identifier before ‘int’
        return 0;
    }
  2. 应该怎样阐述 data_->~T() 的行为?

    当 T 是标量类型(可有 cv 限定的算术、指针、指向成员指针、枚举或 std::nullptr_t 类型)时,它表示伪析构函数调用,即除了对 data_ 取值不做任何事。

    当 T 不是标量类型时,它显式调用了 data_ 的析构函数。

这种行为让 data_->~T() 的调用变得很理想。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题