Understand the behavior of the new-handler
当 operator new
无法满足某一内存分配需求时,它会抛出异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#include <new>
namespace std {
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
}
void out_of_memory() {
std::cerr << "unable to satisfy request for memory.\n";
std::abort();
}
// 当operator new无法满足内存申请时,会不断调用 new-handler 直到找到足够内存
int main() {
std::set_new_handler(out_of_memory);
int* pBigData = new int[10000000000];
}
|
一个优秀的 new-handler
函数需要:
- 让更多内存可被使用
- 安装另一个
new-handler
- 卸除
new-handler
- 抛出
bad_alloc
(或派生自 bad_alloc
)的异常
- 不返回
abort()
or exit()
令一个 class 提供自己的set_new_handler
和operator new
,就可以获得该 class 专属的 new-handler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
class Widget {
public:
static std::new_handler set_new_handler(std::new_handler p) throw();
static void* operator new(std::size_t size) throw(std::bad_alloc);
private:
static std::new_handler currentHandler;
};
std::new_handler Widget::currentHandler = 0;
std::new_handler Widget::set_new_handler(std::new_handler nh) throw() {
std::new_handler oldHandler = currentHandler;
currentHandler = nh;
return oldHandler;
}
// RAII 管理 new_handler
class NewHandlerHolder {
public:
explicit NewHandlerHolder(std::new_handler nh) : handler(nh) {}
~NewHandlerHolder() { std::set_new_handler(handler); }
private:
std::new_handler handler;
NewHandlerHolder(const NewHandlerHolder&);
NewHandlerHolder& operator=(const NewHandlerHolder&);
};
// 模板化
template <typename T>
class NewHandlerSupport {
public:
static std::new_handler set_new_handler(std::new_handler nh) throw();
static void* operator new(std::size_t size) throw(std::bad_alloc);
private:
std::new_handler current_handler;
};
template <typename T>
std::new_handler NewHandlerSupport<T>::set_new_handler(
std::new_handler nh) throw() {
std::new_handler old = current_handler;
current_handler = nh;
return old;
}
template <typename T>
void* NewHandlerSupport<T>::operator new(std::size_t size) throw(
std::bad_alloc) {
NewHandlerHolder h(std::set_new_handler(current_handler));
return :: operator new(size);
}
template <typename T>
std::new_handler NewHandlerSupport<T>::current_handler = 0;
|
Understand when it makes sense to replace new and delete
替换编译器提供的 operator new
或 operator delete
的几种理由:
- 用来检测运用上的错误
- 为了强化效能
- 为了收集使用上的统计数据
- 为了增加分配和归还的速度
- 为了降低缺省内存管理器带来的空间额外开销
- 为了弥补缺省分配器中的最佳齐位
- 为了将相关对象成簇集中
- 为了获得非传统的行为
Adhere to convention when writting new and delete
operator new
:实现一致性 operator new
必须返回正确的值,内存不足时必要调用new-handler
函数,必须又对付零内存需求的准备,还需避免不慎掩盖非正常形式的 new。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
void* operator new(std::size_t size) throw(std::bad_alloc) {
using namespace std;
if (size == 0) {
size = 1;
}
void* p;
while (true) {
if ((p = malloc(size))) {
return p;
}
new_handler global_handler = set_new_handler(0);
set_new_handler(global_handler);
if (global_handler) {
(*global_handler)();
} else {
throw std::bad_alloc();
}
}
}
|
operator new
应该内含一个无穷循环,并在其中尝试分配内存,如果无法满足内存需求,就该调用 new-handler
。它也应该有能力处理 0 bytes 申请。 Class 专属版本还应该处理 “比正确大小更大的(错误)申请”。
operator delete
应该在收到 null 指针时不做任何事。
其他的一些讨论
Pay attention to compiler warnings
Familiarize yourself with the standard library, including TR1
Before TR1:
- STL
- IOStream
- i18n
- numeric
- exception hierarchy
- C89
TR1:
- smart pointers
- tr1::function
- tr1::bind
- hash tables
- regular expression
- tuples
- tr1::array
- tr1::mem_fn
- tr1::reference_wrapper
- random number
- math functions
- C99
- type traits
- tr1::result_of
Familiarize yourself with Boost