effective C++ 学习 (Customizing new and delete)
来源:互联网 发布:网络拥塞控制方法 编辑:程序博客网 时间:2024/06/05 22:50
effective C++ 学习 (Customizing new and delete)
Item 49: Understand the behavior of the new-handler.
1. Heap that containers in STL useis directly managed by allocator object but not new and delete.
2. “operator new” will call the functionthat appointed by users before it throws exception. Users can appoint theprocessing functions by set_new_handler, as following:
namespace std
{
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
}
Note:the parameter of this function is user-defined handler, and the return value isalso a function pointer, which points the handler function that was used beforecalling the function set_new_handler.
3. A good new-handler functionshould do the following things well:
1) Utilize more memory as soon aspossible;
2) Install the other new-handler;
3) Uninstall new-handler by nullpointer ;
4) Throw bad_alloc, this exceptioncan’t be captured by “operator new”;
5) No return to be more flexible.It is more convenient for you to implement new-handler.
4. Defining exclusive(专属的) new-handlers for user-defined classes.
#include<iostream>
class NewHandlerHolder
{
public:
explicitNewHandlerHolder(std::new_handler nh):handler(nh){}
~NewHandlerHolder(){std::set_new_handler(handler);}// recovery old new-handler
private:
std::new_handler handler;// save old new-handler
NewHandlerHolder(constNewHandlerHolder&);
NewHandlerHolder& operator=(constNewHandlerHolder&);
};
class Widget
{
public:
staticstd::new_handler set_new_handler(std::new_handler p)throw();
static void* operator new[](size_t size);
private:
staticstd::new_handler currentHandler;
};
//static members must be defined outside of class
//except static const int member
std::new_handlerWidget::currentHandler = 0;
std::new_handlerWidget::set_new_handler(std::new_handler p) throw()
{
std::new_handler oldHandler = currentHandler;
currentHandler = p;
returnoldHandler;
}
void* Widget::operatornew[](std::size_t size) throw(std::bad_alloc)
{
NewHandlerHolder //install new new-handlerof Widget
h(std::set_new_handler(currentHandler));//and save old new-handler
return ::operatornew[](size); //allocatememory
} //recover old global new-handler
void outOfMem()
{
std::cerr<<"Unableto satisfy request for memory\n";
std::abort();
}
int main()
{
Widget::set_new_handler(outOfMem);
Widget* pw1 = newWidget[2000000000];
Widget::set_new_handler(0);
Widget* pw2 = newWidget[1000000000];
return 0;
}
Note: these are the following problems neededto pay attention:
1) The old new-handler functionpointer should be regarded as resource to be managed by RAII (Resource Acquisition Is Initialization).It is the NewHandlerHolder class that is used to manage old new-handlerfunction pointer;
2) The place of “return ::operatornew[](size); ” will throw exception and the function of outOfMem() will becalled. After that, the destructor of NewHandlerHolder will be called torecover new-handler function of system.
3) All objects of a class sharethe same static member variables. If the static member variables belong to baseclass, all objects of derived classes will shared the same static membervariables.
5. The operators above is similarto all user-defined classes, so the choice of designing a base class with styleof “mixin” will be a good choice. We had better to implement it by template.Before we start to write, let’s analysis the reasons:
#include<iostream>
//template<typename T>
class Base
{
public:
virtual~Base(){}
virtual void outBaseMemberPointer(){std::cout<<&this->m_base<<std::endl;}
private:
static int m_base;
};
//template<typename T>
int Base/*<T>*/::m_base= 0;
class Derived1: public Base/*<Derived1>*/
{
};
class Derived2: public Base/*<Derived2>*/
{
};
int main()
{
Derived1 test1;
Derived2 test2;
test1.outBaseMemberPointer();
test2.outBaseMemberPointer();
}
Result:
Note: As shown in the picture, the derivedobjects of test1 and test2 share the same static member variable of m_base dueto the same address. Obviously, if we use normal base class to encapsulate (封装) “operatornew” and “static std::new_handler set_new_handler(std::new_handler p)”, its derived classes will share the same “m_base” static membervariables. In order to achieve each derived class have own static membervariables, we should use template.
#include<iostream>
template<typename T>
class Base
{
public:
virtual ~Base(){}
virtual voidoutBaseMemberPointer(){std::cout<<&this->m_base<<std::endl;}
private:
static int m_base;
};
template<typename T>
intBase<T>::m_base = 0;
class Derived1: public Base<Derived1>
{
};
class Derived2: public Base<Derived2>
{
};
int main()
{
Derived1test1;
Derived2test2;
test1.outBaseMemberPointer();
test2.outBaseMemberPointer();
}
Note: we discover the derived objects havedifferent static member variables.
6. The base class with the styleof “mixin”:
#include<iostream>
class NewHandlerHolder
{
public:
explicitNewHandlerHolder(std::new_handler nh):handler(nh){}
~NewHandlerHolder(){std::set_new_handler(handler);}// recovery old new-handler
private:
std::new_handler handler;// save old new-handler
NewHandlerHolder(constNewHandlerHolder&);
NewHandlerHolder& operator=(constNewHandlerHolder&);
};
template<typename T>
class NewHandlerSupport
{
public:
staticstd::new_handler set_new_handler(std::new_handler p)throw();
static void*operator new(size_t size)throw(std::bad_alloc);
private:
staticstd::new_handler currentHandler;
};
// static member variables must be defined outside of class
template<typename T>
std::new_handlerNewHandlerSupport<T>::currentHandler = 0;
template<typename T>
std::new_handlerNewHandlerSupport<T>::set_new_handler(std::new_handler p)throw()
{
std::new_handler oldHandler = currentHandler;
currentHandler = p;
returnoldHandler;
}
template<typename T>
void* NewHandlerSupport<T>::operatornew(size_t size)throw(std::bad_alloc)
{
NewHandlerHolderh(std::set_new_handler(currentHandler));
return ::operatornew(size);
}
class Widget: publicNewHandlerSupport<Widget>
{
};
void outOfMem()
{
std::cerr<<"outof memory.\n";
std::abort();
}
int main()
{
Widget::set_new_handler(outOfMem);
Widget* w = newWidget;
}
Note: these are some the followingproblems:
1) Different derived classes havedifferent entity (实体) due todifferent template parameters;
2) Use the derived classes toinstantiate base classes, which is named as curiously recurring templatepattern(CRTP 怪异的循环模板模式);
3) Use “std::nothrow” not to ensurethat no exceptions are thrown;
4) The size of new operator issize of member variables after aligned.
Item 50: Understand when it makes sense to replace new anddelete.
1. The reasons of replacingsystem-defined “operator new” and “operator delete” with user-defined “operatornew” and “operator delete”:
1) Detecting runtime errors; sometimesthe mistakes of overruns(写入点在分配区块尾端之后) andunderruns(写入点在分配区块起点之前) would happen, howeverfor user-defined operator new can achieve larger space to place byte patterns(signatures) to detect these mistakes.
2) In order to enforce function;custom memory allocation policy for special application situation.
3) Collect using data. Know thesize of allocation memory, memory life and order of memory allocation ofrelease (e.g.LIFO, FIFO, random in and out). It is easy for user-definedoperator new to collect;
4) Increase speed of memoryallocation and release; first of all you need to know which function your programbottlenecks lie;
5) In order to decrease the extra expensefor default memory manager;
6) In order to make up thesuboptimal alignment of default memory manager;
7) In order to gather relativedata to less pages;
8) In order to do something thatdefault operator new and operator delete don’t do, like manager shared memoryby C API, define operator delete to release memory covered by 0 to strengthendata safety.
2. Defining own operator new andoperator delete, you must consider some details like alignment, system portabilityand thread safety etc.
Item 51: Adhere to convention when writing new and delete.
1. Non-member operator newpseudocode(伪码):
void* operatornew(std::size_t size) throw(std::bad_alloc)
{
using namespace std;
if(size == 0)
{
size = 1;
}
while(true)
{
//try toallocate size bytes
if(Assignmentsuccess)
return(a pointer that points memory aligned);
//allocate fail,find current new-handling function
new_handler globalHandler =set_new_handler(0);
set_new_handler(globalHandler);
if(globalHandler)((*globalHandler)());
else throw std::bad_alloc();
}
}
Note: in order to make the program breakfrom “while(true)”, the following things need to be done:
1) Allocate memory successfully;
2) New-handling must do thefollowing things:
(1. Make more memory be used;
(2. Install another new-handling;
(3. Uninstall new-handler;
(4. Throw bad_alloc exception.
2. When the “operator new” of base class is derived, it will bring errors that it is calledby derived classes due to difference between base class and derived class.
void* Base::operatornew(std::size_t size) throw(std::bad_alloc)
{
if(size != sizeof(Base))
return ::operatornew(size);
}
Note: if the size errors happen, we callthe standard “operatornew”. The following problemsneed to be noticed:
1) The result of sizeof(Base) ismore than 0;
2) If the size is 0, the standard“operatornew” will be able to dealwith this question well.
3. If you need to implement “operator new[]”, what you should only do is to allocate some raw memory (未加工的内存), because you cannot know the size of an object and the number ofobjects.
4. If you design a delete, youneed to deal with the situation when the pointer is 0, as following:
void operatordelete(void *rawMemory)throw()
{
if(rawMemory== 0) return;
now, returnmemory that rawMemory points
}
5. If “operator new” hand in the allocationoperation with error size, your “operatordelete” should do too, asfollowing:
void Base::operatordelete(void*rawMemory, std::size_t size)throw()
{
if(rawMemory== 0) return;
if(size != sizeof(Base))
{
::operatordelete(rawMemory);
return;
}
now, returnmemory that rawMemory points
return;
}
Note: if there’s no virtual destructor inBase class, C++ may transmit a wrong size, which is one of reasons why weshould use virtual destructor in base class.
Item 52: Write placement delete if you write placementnew.
1. “placement new” and “placementdelete” represents the versions of “operator new” and “operator delete” withextra parameters. For example:
void*operatornew(std::size_t,void* pMemory)throw();
Note: there are a lot of times, the placement new represents thefunction above, but in general it denotes operator new with extra parameters. Thedifference of this version of placement new is that it can assign memory on thespecified location.
2. Write placement delete if youwrite placement new. When we assign memory by using “operatornew”, there are two operatorsrunning. One is to call “operatornew” to assign memory, anotherone is to call the constructor of the class. If the constructor throwsexceptions, system need to recover state before “operatornew” was called, which isdone by system during running time because users don’t have the pointers thatpoint to the memory. If you assign memory by placement new, system must useplacement delete corresponding to placement new to release the memory.Therefore you must write placement delete if you have written placement new.
class Widget
{
public:
static void* operator new(std::size_t size, std::ostream& logStream)throw(std::bad_alloc);
};
Widget*pw = new (std::cerr) Widget;
3. If you write placement new, youneed to write placement delete, which is all right, but if you assign memorysuccessfully and you need to release it afterwards, so you also need a normaloperator delete, like this:
class Widget
{
public:
static void* operator new(std::size_t size, std::ostream& logStream)throw(std::bad_alloc);
static void operator delete(void* pMemory)throw();
static void operator delete(void* pmemory,std::ostream& logStream)throw();
};
4. Avoid covering the standardversion unconsciously.
“operator new” in the global scope.
void* operatornew(std::size_t)throw(std::bad_alloc);
void* operatornew(std::size_t,void*)throw();
void* operatornew(std::size_t,const std::nothrow_t&)throw();
If you don’t want to cover the “operator new” in the globalscope, you can implement it by the following base class and declare them byusing in the derived classes.
classStandardNewDeleteForms
{
public:
//normal new/delete
static void* operator new(std::size_tsize)throw(std::bad_alloc)
{ return ::operatornew(size); }
static void operator delete(void* pMemory)throw()
{ ::operator delete(pMemory);}
//placement new/delete
static void* operator new(std::size_tsize,void *ptr) throw()
{ return ::operatornew(size,ptr);}
static void operator delete(void* pMemory,void*ptr) throw()
{ return ::operatordelete(pMemory,ptr);}
// nothrow new/delete
static void* operator new(std::size_tsize,const std::nothrow_t& nt) throw()
{ return ::operatornew(size,nt);}
static void operator delete(void * pMemory,conststd::nothrow_t& nt) throw()
{ return ::operatordelete(pMemory);}
};
class Widget:public StandardNewDeleteForms
{
public:
// get standard forms by using
using StandardNewDeleteForms::operatordelete;
using StandardNewDeleteForms::operatornew;
static void* operator new(std::size_tsize, std::ostream& logStream)throw(std::bad_alloc);
static void operator delete(void* pMemory)throw();
static void operator delete(void* pmemory, std::ostream& logStream)throw();
};
int main()
{
Widget*pw = new (std::cerr) Widget;
return 0;
}
- effective C++ 学习 (Customizing new and delete)
- (Effective C++)第八章 定制new和delete(Customizing new and delete)
- Effective C++ 读书笔记之Part8.Customizing new and delete
- Chapter 8. Customizing new and delete
- Effective C++(Item3) Prefer new and delete to malloc and free
- c++new and delete
- More Effective C++:不同new和delete
- More Effective C :理解new和delete
- Effective C++(八)定制new和delete
- More Effective C++:理解new和delete
- effective C++: 8.定制new和delete
- Effective C++(八)定制new和delete
- 《Effective C++》定制new和delete
- 《Effective C++》学习笔记条款16 成对使用new和delete时要采取相同形式
- 《More Effective C++》学习心得(六)各种new和delete操作符
- C++之成对使用的new和delete时采取相同形式(16)---《Effective C++》
- C++之了解new和delete的合理替换时机(50)---《Effective C++》
- C++之编写new和delete时需要固守常规(51)---《Effective C++》
- JavaScript setTimeout 的原理
- cmake指令详解
- 出于好奇,我去暗网里瞧了瞧 —— 你就别去了
- vue-resource jsonp接口传参-json传参
- oracle 12c rac ocr和votedisk管理
- effective C++ 学习 (Customizing new and delete)
- Unity3D 摄像机(Camera)属性详解
- HIVE分区表新增字段后新增字段值为空,需要带分区加字段
- php变量范围介绍
- CentOS7+Apache+MySQL+PHP安装
- Linux 的 Kill -9命令
- Excel对比两列数据相同的在第三列打印出来
- 解决IE浏览器下:td标签上有position: relative;与background-color属性时td边框消失
- linux 查看系统信息命令(比较全)