【发布时间】:2014-12-24 15:23:24
【问题描述】:
我知道那里很少有 C++ 常见问题解答(以及关于 SO 的答案)说没有必要检查纯新表达式的返回值是否为 null,因为纯新表达式通过抛出异常表示失败。他们基本上声明普通的 new-expression 永远不会返回 null。 (“普通新表达式”是指不是 nothrow 的新表达式)。
然而,尽管这看起来是一个非常基本的问题,但我突然意识到,当他们给出这个答案时,我不明白他们做出了什么具体假设(如果有的话)。
特别是,我想知道是否允许我重载::operator new 的基本纯格式以始终返回空指针,因此希望所有使用该运算符的纯新表达式现在也将返回空指针。
根据语言规范,如果我的::operator new 被声明为不抛出,那么我可以/应该通过返回一个空指针来指示内存分配失败。所以,让我们这样做
void *operator new(size_t s) throw() {
return 0;
}
int main() {
int *i = new int;
}
在我的实验中,上面的 new 表达式确实成功地返回了一个空指针。那么,我是否违反了上述代码中的任何规则?将普通的 ::operator new 声明为不抛出是否合法?
如果上面的代码没问题,那么我假设当有人声明一个普通的新“从不返回空指针”时,他们会假设标准库提供的 ::operator new 版本没有被替换。这个假设正确吗?
【问题讨论】:
-
这个讨论还有另一个方面 - 即使标准明确允许您返回
nullptr/0,正如您所说的那样,处理0s 所需的标准库?我敢打赌它们不是——而且实现也不是——所以编写一个返回 0 的::operator new的程序是不切实际的。例如20.8.9.1/4 需要std::allocate::allocatethrowstd::bad_alloc如果无法获得存储 - 它会(通常是冗余地)检查 null,还是信任::operator new抛出? -
new的非抛出版本不需要不同的签名吗?void* operator new(std::size_t size);不能返回空指针,即使重新定义也必须抛出空指针。 -
标准库将使用
::new T进行标准构造和::new (static_cast<void*>(get_allocator()(1)) T进行放置,并且这些表单总是调用抛出分配函数(无论是否已被替换)。 -
对于它的价值,我认为所有那些可替换和可重载的分配函数都是对语言的错误设计,就像动态数组一样。所有这些都应该在库中使用分配器完成,然后您可以从核心语言中切出一大块没人会错过的内容。
标签: c++ null new-operator standards-compliance