c – 为什么我们可以将可选参数传递给新表达式而不是删除表达式?

在stackoverflow上已经就此主题提出了一些问题,但我没有看到任何解释限制删除表达式背后的基本原理.

为澄清这个问题,我试图收集事实,因为我已经在以下三个评论中理解了这些事实.

备注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);
}

因此我们知道用简单的语法“删除t;”我们可以隐式地自动调用任何“operator 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(...);
}

…,不幸的是我们知道“删除(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”定义一个,并且您必须小心,因为您无法处理全局版本和类成员版本的相同方式).

总结一下:
我们有一个通用的新表达式但没有一般的删除表达式.
你知道看起来像这种不一致的背后的理由吗?

最佳答案 请注意,由于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));

然后是破坏功能:

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)...);
    }
}

Live Demo

我不知道没有一般删除表达式的理由.也许它在解析某处时引入了歧义……

点赞