我正在开发一个不使用异常的项目,应该保持这种状态。 为了使用我自己的内存管理器,我重载了(overrid也许会更正确)new运算符。在我的内存管理器中,如果分配失败 - 返回NULL。 现在altough new运算符返回NULL,正在调用构造函数,然后我得到一个seg错误,因为我没有分配内存。 我想要的功能是如果new运算符返回NULL,那么不应该调用构造函数(之后我会检查对象是否已成功初始化)。
我希望它可以像这样工作:
set height 0
谢谢!
答案 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 运算符。
自 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 最终根据他们自己的回答使用了这个。