运算符新重载c ++,无异常处理失败

时间:2015-09-24 11:49:56

标签: c++ operator-overloading new-operator

我正在开发一个不使用异常的项目,应该保持这种状态。 为了使用我自己的内存管理器,我重载了(overrid也许会更正确)new运算符。在我的内存管理器中,如果分配失败 - 返回NULL。 现在altough new运算符返回NULL,正在调用构造函数,然后我得到一个seg错误,因为我没有分配内存。 我想要的功能是如果new运算符返回NULL,那么不应该调用构造函数(之后我会检查对象是否已成功初始化)。

我希望它可以像这样工作:

set height 0

谢谢!

4 个答案:

答案 0 :(得分:7)

您需要调用new (nothrow),如下所示:

myObject* = new (std::nothrow) myObject(...);

然后,您需要覆盖采用operator new的那个,而不是覆盖常规std::nothrow_t。有关详情,请参阅此处:http://www.cplusplus.com/reference/new/nothrow/

没有operator new的常规nothrow不应该在失败时返回null,而应该抛出。由于您不允许抛出,因此无法实现这些运算符(除非在失败或类似情况下调用abort())。

最后,在编译期间完全禁用异常可能会有所帮助。我希望当时会发现这种错误(我不确定)。

答案 1 :(得分:1)

最终解决方案是在新函数的decleration结束时添加'throw()'。

void* operator new (size_t size) throw()

可以在常规的新的或新的(nothrow)中完成。在我的imlpementation中将它添加到常规new会导致所需的效果,即任何'new'调用将能够在失败时返回NULL。

还可以选择在编译中使用'--force_new_nothrow'标志。

更多关于两者都可以找到 here

答案 2 :(得分:0)

您必须手动完成此操作,即

object * create_object(MemoryManager & mem, ...) {
   void * chunk = mem.get_memory_for_object();
   if (chunk == NULL) return NULL;
   return new (chunk) object(...); // inplace new 
}

答案 3 :(得分:0)

我假设您想要提供自定义的、特定于类的分配函数,而不是在全局命名空间中重载 new 运算符。

tl;博士

自 C++11 起:使用 operator new 声明您的自定义 noexcept,一切正常。

void* T::operator new (size_t size) noexcept;

完整答案

虽然 John 给出的当前接受的答案提出了一个可行的解决方案,但它暗示 std::nothrow 标记是必要的,没有它就无法完成,这是错误的。

此答案只是@dyp 的(正确)评论,已扩展为完整答案并附有标准中的当前引用。

C++11 standard 在 [basic.stc.dynamic.allocation] 第 3 段中说:

<块引用>

如果使用非抛出异常规范 (15.4) 声明的分配函数未能分配存储,则应返回空指针。未能分配存储的任何其他分配函数应仅通过抛出与 std::bad_alloc (18.6.2.1) 类型的处理程序 (15.3) 匹配的类型的异常来指示失败。

多年来,这句话已经被改写,但在语义上等效的东西已经出现在 C++14、C++17 和 C++20 中。 The current working draft for C++23 在 [basic.stc.dynamic.allocation] 中有这一段:

<块引用>

具有非抛出异常规范 (14.5) 的分配函数通过返回空指针值指示失败。任何其他分配函数从不返回空指针值,并且仅通过抛出类型与 std::bad_alloc (17.6.4.1) 类型的处理程序 (14.4) 匹配的异常 (14.2) 来指示失败。

“非抛出异常规范”在 [except.spec] 中定义。如果将 noexcept 添加为声明的后缀,则函数具有此规范。因此,问题中给出的代码可以完全正常工作,但必须使用 noexcept 声明自定义 new 运算符:

void* T::operator new (size_t size) noexcept;

或者,在 C++17 之前,使用 throw() 代替 noexcept 也有效,但它已在 C++11 中被弃用并在 C++20 中被移除。这是 C++11 之前要走的路。 OP 最终根据他们自己的回答使用了这个。