c++模板函数,替换失败跳过实现

C++ template function, substitution failure skip the implementation

本文关键字:失败 实现 替换 函数 c++      更新时间:2023-10-16

我有下面的代码只是为了测试,模板函数使用了两次,第一次它是ok的。在第二种情况下,我创建一个指针,并将指针作为引用传递给模板函数。我期望"obj.~T()"行在编译时失败。但实际上代码编译和运行得很好。当我调试该函数时,程序只是跳过obj.~T();我用的是VC10。

我的问题是:
1. 这是一种预期行为吗?如果它是基于c++标准的哪个部分?
2. 这种行为有什么利弊吗?在我的情况下,它是好的,因为没有编译错误,也没有运行时错误。但是可能会有一些我不知道的情况,但是会损坏代码。

谢谢

template<typename T>
void ptrDest(T& obj)
{
  obj.~T();
}
class Dummy
{
public:
  Dummy(){}
  ~Dummy(){ cout << "dest" <<endl;}
};
int main()
{
  Dummy d;
  ptrDest(d);
  Dummy* pd = new Dummy();
  ptrDest(pd);
  return 0;
}

这是一个显式析构函数调用,它是一个有效的操作,尽管不一定被认为是一个好的实践。如果可能的话,考虑使用有作用域的变量。

在第二个调用中,您实际上试图调用指针的析构函数,而不是指向对象的析构函数,这就是它跳过它的原因。但是,请注意,在第二次调用之后仍然分配Dummy对象,并且在所有情况下都将泄漏。

模板替换导致伪析构函数调用表达式或函数调用析构函数。它们在语言语法中是相同的东西,但在语义上不同:

  • 伪析构函数调用(c++ 11§5.2.4)是允许的基本类型,如指针,它不做任何事情。

  • 显式析构函数调用是经过名称查找并形成函数调用表达式的函数调用(c++ 11§5.2.2)。

任何与模板中伪析构函数调用的语法相匹配的内容也可能是格式良好的函数调用(显式析构函数调用),反之亦然。

因此,如果您看到d的析构函数有两条消息,而dp的析构函数没有消息,那么您正在观察预期的行为。

没有编译错误
-行为是正确的,因为obj.~T();表示它是对对象的函数调用。调用函数不是编译错误。

代码运行正常
-此行为未定义。为什么你没有得到任何错误运行是因为它是一个非常简单的类,甚至没有基本类型的数据成员,更不用说复杂类型的成员。
这里发生的事情是,在Main中,对象d的析构函数被调用了两次。一次是调用ptrDest,第二次是退出Main函数时的隐式析构函数。析构函数是如此简单,编译器将其代码内联。这只是一个无伤大雅的理由。如果在复杂类中使用析构函数对数据成员进行操作,则肯定会导致问题。