【发布时间】:2015-01-14 18:21:14
【问题描述】:
考虑以下代码:
#include <new>
#include <malloc.h>
#include <stdio.h>
void * operator new(size_t size) {
void *res;
if (size == 1) {
res = NULL;
} else {
res = malloc(size);
}
fprintf(stderr, "%s(%zu) = %p\n", __PRETTY_FUNCTION__, size, res);
if (res == NULL) throw std::bad_alloc();
return res;
}
void * operator new(size_t size, const std::nothrow_t&) {
void *res;
if (size == 1) {
res = NULL;
} else {
res = malloc(size);
}
fprintf(stderr, "%s(%zu) = %p\n", __PRETTY_FUNCTION__, size, res);
return res;
}
void operator delete(void *ptr) {
fprintf(stderr, "%s(%p)\n", __PRETTY_FUNCTION__, ptr);
free(ptr);
}
void operator delete(void *ptr, const std::nothrow_t&) {
fprintf(stderr, "%s(%p)\n", __PRETTY_FUNCTION__, ptr);
free(ptr);
}
class Foo { };
class Bar {
public:
Bar() : ptr(new Foo()) {
fprintf(stderr, "%s: ptr = %p\n", __PRETTY_FUNCTION__, ptr);
}
Bar(const std::nothrow_t&) noexcept : ptr(new(std::nothrow) Foo()) {
fprintf(stderr, "%s: ptr = %p\n", __PRETTY_FUNCTION__, ptr);
}
~Bar() noexcept {
delete ptr;
}
Foo *ptr;
};
class Baz {
public:
Baz() : ptr(new Foo()) {
fprintf(stderr, "%s: ptr = %p\n", __PRETTY_FUNCTION__, ptr);
}
~Baz() {
delete ptr;
}
Foo *ptr;
};
int main() {
Bar *bar = new(std::nothrow) Bar(std::nothrow_t());
if (bar != NULL) {
delete bar;
} else { fprintf(stderr, "bad alloc on Bar(std::nothrow_t())\n"); }
fprintf(stderr, "\n");
try {
bar = new(std::nothrow) Bar();
delete bar;
} catch (std::bad_alloc) { fprintf(stderr, "bad alloc on Bar()\n"); }
fprintf(stderr, "\n");
try {
Baz *baz = new Baz();
delete baz;
} catch (std::bad_alloc) { fprintf(stderr, "bad alloc on Baz()\n"); }
}
这会产生以下输出:
void* operator new(size_t, const std::nothrow_t&)(8) = 0x1fed010
void* operator new(size_t, const std::nothrow_t&)(1) = (nil)
Bar::Bar(const std::nothrow_t&): ptr = (nil)
void operator delete(void*)((nil))
void operator delete(void*)(0x1fed010)
void* operator new(size_t, const std::nothrow_t&)(8) = 0x1fed010
void* operator new(std::size_t)(1) = (nil)
void operator delete(void*, const std::nothrow_t&)(0x1fed010)
bad alloc on Bar()
void* operator new(std::size_t)(8) = 0x1fed010
void* operator new(std::size_t)(1) = (nil)
void operator delete(void*)(0x1fed010)
bad alloc on Baz()
如您所见,尽管分配 Foo 失败,但分配第一个 Bar 成功。 Bar 的第二次分配和 Baz 的分配通过使用 std::bad_alloc 正确失败。
现在我的问题是:如何制作“new(std::nothrow) Bar(std::nothrow_t());”当 Foo 分配失败时释放 Bar 的内存并返回 NULL?依赖倒置是唯一的解决方案吗?
【问题讨论】:
-
语法必须是
new(std::nothrow) Bar(std::nothrow_t());吗?Bar::create( std::nothrow_t{} )怎么样?还是create<Bar>( std::nothrow_t{} )? -
你的意思是class Bar { public: static Bar * create();私人:酒吧(Foo *foo); }?那将使用依赖倒置。
-
不,
Bar仍然可以创建Foo。您只需在创建者函数中检测到失败并取消分配并返回 null。细节不如我们不再使用new的事实重要,这对您来说可能无法接受。 -
好的。与完全依赖倒置略有不同。但是为了以一般方式工作,类需要一个 is_good() 方法,必须检查构造函数和析构函数是否必须处理初始化错误的类。我希望仍然可以从您的自动清理中受益,但有例外。
标签: c++ c++11 constructor new-operator nothrow