在stackoverflow上已经就这个主题提出了一些问题,但我还没有看到任何人解释delete表达式限制背后的基本原理
为了澄清这个问题,我试图收集我在以下三句话中理解的事实。
备注1:通用新表达式
让我们考虑任何"operator new"(无论它是默认的全局运算符、覆盖默认全局运算符的版本、重载版本还是类成员版本)。假设我们还有一个匹配的"operator delete"。假设原型如下:
void* operator new(size_t, T1, T2, ..., Tn);
void operator delete(void*, T1, T2, ..., Tn);
我们知道,当程序员键入一个新的表达式时:
T* t = new(t1, ..., tn) T();
(其中t1、…、tn的类型分别为t1、…、tn)
编译器会自动将这一行替换为以下内容:
T* t;
void* raw = operator new(sizeof(T), t1, ..., tn); // or T::operator new(...)
try {
t = new(raw) T();
}
catch (...) {
operator delete(raw, t1, ..., tn); // or T::operator delete(...)
throw;
}
备注2:删除表达式-在某些情况下是合法的
我们知道,当程序员键入这个删除表达式时:
delete t;
(其中t的类型为t)
编译器会自动将这一行替换为以下内容:
if (t) {
t->~T();
operator delete(t); // or T::operator delete(t);
}
因此,我们知道,使用简单的语法"delete t;",我们可以隐式地自动调用采用与默认全局参数相同的参数的任何"运算符delete"(它可以是默认全局参数本身、覆盖默认全局参数的版本,或采用与默认全球参数相同参数的类成员版本)。
备注3:删除表达式-通常是非法的
让我们考虑不采用与默认全局参数相同的参数的任何"运算符删除"(它可以是全局重载版本或类成员版本)。假设原型如下:
void operator delete(void*, T1, ..., Tn);
我们本来想写一个通用的删除表达式:
delete(t1, ..., tn) t;
希望编译器能自动将其替换为:
if (t) {
t->~T();
operator delete(t, t1, ..., tn); // or T::operator delete(...);
}
不幸的是,我们知道"delete(t1,…,tn)t;"是非法的!
因此,通常建议编写一个模板函数,如:
template<typename T> void destroy(T* t, T1 t1, ..., Tn tn) {
if(t) {
p->~T();
operator delete(t, t1, ..., tn); // or T::operator delete(...); ?!
}
}
这可能会有问题(您必须为每个"operator delete"定义一个,并且必须小心,因为您不能以相同的方式处理全局版本和类成员版本)。
综上所述:
我们有一个通用的new表达式,但没有通用的delete表达式。你知道这种不一致背后的原因吗?
注意,由于C++11和可变模板,您可以将destroy
写一次为:
// Helper to define has_operator_delete traits
template <typename T, typename ...Ts> std::false_type has_operator_delete_impl(...);
template <typename T, typename ...Ts> auto has_operator_delete_impl(int)
-> decltype(std::declval<T>().operator delete(nullptr, std::declval<Ts>()...),
std::true_type{});
// traits to know if T has operator delete(void*, Ts...)
template <typename T, typename ...Ts>
using has_operator_delete = decltype(has_operator_delete_impl<T, Ts...>(0));
然后destroy
起作用:
template<typename T, typename ...Ts>
std::enable_if_t<has_operator_delete<T, Ts...>::value>
destroy(T* t, Ts&&... ts)
{
if (t) {
t->~T();
T::operator delete(t, std::forward<Ts>(ts)...);
}
}
template<typename T, typename ...Ts>
std::enable_if_t<!has_operator_delete<T, Ts...>::value>
destroy(T* t, Ts&&... ts)
{
if (t) {
t->~T();
operator delete(t, std::forward<Ts>(ts)...);
}
}
实时演示
我不知道为什么没有一个通用的删除表达式。也许它在解析中引入了歧义。。。