Item 49: Understand the behavior of the new-handler.

  1. 1. Part 8: Customizing new and delete
  2. 2. Things To Remember
  3. 3. Key Words
  4. 4. Code

This article is one of <Effective C++> reading notes.

Part 8: Customizing new and delete

Item 49: Understand the behavior of the new-handler.


Things To Remember

  • set_new_handler allows you to specify a function to be called when memory allocation requests cannot be satisfied.
  • Nothrow new is of limited utility, because it applies only to memory allocation; subsequent constructor calls may still throw exceptions.

Key Words

curiously recurring template pattern (CRTP) 怪异的循环模版模式:

The curiously recurring template pattern (CRTP) is a C++ idiom in which a class X derives from a class template instantiation using X itself as template argument.

c++ Template CRTP

关于c++ template多态——CRTP 模式


Code

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <new>
#include <stdlib.h>
class NewHandlerHolder
{
public:
trueexplicit NewHandlerHolder(std::new_handler nh) : handler(nh) { };
true~NewHandlerHolder() { std::set_new_handler(handler); } // release it
private:
truestd::new_handler handler; // remember it
trueNewHandlerHolder(const NewHandlerHolder&); // prevent copying
trueNewHandlerHolder& operator=(const NewHandlerHolder&);
};
// The NewHandlerSupport template never uses its type parameter T.
// All we need is a different copy of NewHandlerSupport - in particular,
// it's static data member currentHandler - for each class that
// inhreits from NewHandlerSupport.
template<typename T>
class NewHandlerSupport
{
public:
truestatic std::new_handler set_new_handler(std::new_handler p) throw();
truestatic void* operator new(std::size_t size) throw(std::bad_alloc);
private:
truestatic std::new_handler currentHandler;
};
template<typename T>
std:: new_handler NewHandlerSupport<T>::set_new_handler(std::new_handler p) throw()
{
truestd::new_handler oldHandler = currentHandler;
truecurrentHandler = p;
truereturn oldHandler;
}
template<typename T>
void* NewHandlerSupport<T>::operator new(std::size_t size) throw(std::bad_alloc)
{
trueNewHandlerHolder h(std::set_new_handler(currentHandler));
truereturn ::operator new(size);
}
template<typename T>
std::new_handler NewHandlerSupport<T>::currentHandler = 0;
//
class Widget : public NewHandlerSupport<Widget>
{
true// ...
};
void outOfMem()
{
truestd::cerr << "Unable to satisfy request for memory\n";
trueabort();
}
int main()
{
true// set outOfMem as Widget's new-handling function
trueWidget::set_new_handler(outOfMem);
true// if memory allocation fails, call outOfMem
trueWidget* pw1 = new Widget;
true// if memory allocation fails, call the global new-handling function (if there if one)
truestd::string* ps = new std::string;
true// set the Widget-specific new-handling function to nothing (i.e., null)
trueWidget::set_new_handler(0);
true// if mem. alloc. fails, throw an exception immediately
trueWidget* pw2 = new Widget;
truereturn 0;
}