gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:16:19 26 4
gpt4 key购买 nike

已经在 stackoverflow 上就此主题提出了一些问题,但我还没有看到任何关于删除表达式限制背后的基本原理的解释。
为了澄清这个主题,我试图在以下三个评论中收集我所理解的事实。

备注1:通用新表达式
让我们考虑任何“operator new”(无论它是默认的全局操作符、覆盖默认全局操作符的版本、重载版本还是类成员版本)。假设我们也有一个匹配的“operator delete”。假设原型(prototype)如下:

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;”我们可以隐式自动调用任何采用与默认全局参数相同的参数的“operator delete”(它可以是默认全局参数本身,覆盖默认全局参数的版本,或类成员版本采用与默认全局版本相同的参数)。

备注3:删除表达式——一般来说是非法的
让我们考虑任何不采用与默认全局参数相同的参数的“操作符删除”(它可以是全局重载版本或类成员版本)。假设原型(prototype)如下:

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

Live Demo

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

关于c++ - 为什么我们可以将可选参数传递给新表达式而不是删除表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33896092/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com