new/delete是c++中动态构造对象的表达式 ,一般情况下的new/delete都是指的new/delete表达式,这是一个操作符,和sizeof一样,不能改变其意义。
new/delete表达式的声明如下:
::(optional) new (placement_params)(optional) ( type )initializer(optional)
::(optional) delete expression
除了全局作用符::和初始化参数,还有个 placement_params,这是不常见的,要理解这个参数的作用,就要了解operator new和placement new。
众所周知,new表达式做了两个工作:1.分配内存;2.在分配的内存上调用构造函数构造对象。比如我们分配一个string对象
string *str = new string(“Kian”);
编译器首先调用operator new分配一块内存,类似于malloc,然后在mem上面调用构造函数,
1.void *mem = operator new(sizeof(string));
2. create string at men.
第二步我们是控制不了的,但是operator new却是可以修改的。
Operator new/delete的声明如下:
void* operatornew ( std::size_t count );
void* operatornew ( std::size_t count, const std::nothrow_t& tag);
voidoperator delete ( void* ptr );
voidoperator delete ( void* ptr, const std::nothrow_t& tag);
进入微软、亚马逊,谷歌等美国IT企业工作人才项目,起薪40万,百度搜索(MUMCS)
第二种带参数tag的声明称为nothrow形式,因为现在的operator new如果分配内存失败的话会抛出bad_alloc异常. 有时候我们不想抛出异常,而是根据返回值判断内存分配失败与否,nothrow形式就是这个作用,失败时不抛出异常,而是返回null指针。
我们可以直接重载operator new, 定制自己的内存分配策略,常见的作用是优化内存使用性能。重载operator new不需要看见声明就可以直接使用。我们重定义一个简单的版本:
void* operatornew(std::size_t size){
printf("operator new called, size=%d\n", size);
return malloc(size);
}
voidoperator delete(void *ptr){
printf("operator delete called\n");
free(ptr);
}
int main(){
int *i = newint(2);
delete i;
std::string *str = new std::string("Kian");
delete str;
}
运行结果:
operator new called, size=4
operator delete called
operator new called, size=4
operator new called, size=17
operator delete called
operator delete called
可是有时候我们希望拥有更多的功能,比如记录内存分配释放的位置,用于检测内存错误,或者直接在已有的内存上构造对象,那么必须定义更多参数,这就需要placement new/delete,声明如下.
void* operatornew ( std::size_t count, void* ptr );
void* operatornew ( std::size_t count, user-defined-args... );
voidoperator delete ( void* ptr, void* place);
voidoperator delete ( void* ptr, user-defined-args...);
可以直接在已有内存上构造对象:
void *mem = (void*)malloc(sizeof(int));
int *j = new(mem) int(3);
printf("mem=%p, j=%p, *j = %d\n",mem, j, *j);
free(mem);
运行结果:
mem=0x8a48008, j=0x8a48008, *j = 3
可以看出new直接在mem上面构造了对象。
目前,void* operator new (std::size_tcount, void* ptr )在全局域还不能被重载,但是void* operator new (std::size_tcount, user-defined-args...
)可以自由定义。
比如记录内存分配发生的位置:
void* operatornew(std::size_t size){
printf("operator new called, size=%d\n", size);
return malloc(size);
}
voidoperator delete(void *ptr){
printf("operator delete called\n");
free(ptr);
}
void* operatornew(std::size_t size, char* filename, int line){
printf("new called at %s:%d size=%d \n", filename, line, size);
return ::operatornew(size);
}
voidoperator delete(void *place, char* filename, int line) {
printf("delete called at %s:%d place=%p \n", filename, line, place);
::operator delete(place);
}
int main(){
int *k = new(__FILE__, __LINE__) int(1);
printf("k=%p *k=%d \n", k, *k);
delete k;
}
运行结果:
new called at testnew.cpp:41 size=4
operator new called, size=4
k=0x847f008 *k=1
operator delete called
在每个new中打印了文件名和行号,不过细心的你会发现delete时并没有调用重载的placement delete ,这个delete只有在构造对象时抛出了异常才会调用,我们写一个简单的class来看看:
class ThrowExcept {
public:
ThrowExcept(int v):value_(v){ throw1;}
private:
int value_;
};
int main(){
ThrowExcept *t;
try{
t = new(__FILE__, __LINE__) ThrowExcept(10);
}catch(int&e){
printf("catch exception %d\n", e);
}
}
运行结果:
new called at testnew.cpp:53 size=4
operator new called, size=4
delete called at testnew.cpp:53 place=0x9e2e008
operator delete called
catch exception 1
自定义的delete被正常调用,这么做的原因在于如果构造函数抛出异常,系统正常的operator delete并不知道用户自定义的placement new做了什么,自然也不知道怎么去释放。所以如果自己定义placement new, 一定要定义对应的palcement delete,不然可能出现memory leak。
《effective/more effective c++》
分享到:
相关推荐
new操作符(new operator)和operator new的区别,会很有帮助
operator-sdk环境搭建 我的电脑环境为windows,安装operator-sdk需要自己...其中mercurial和bazaar我都没装,operator-sdk也编译安装成功了。 $ go get -d github.com/operator-framework/operator-sdk # This will d
chaosblade-operator镜像
flink-kubernetes-operator-1.7.0-src.tgz,flink-kubernetes-operator-1.7.0-src.tgz,flink-kubernetes-operator-1.7.0-src.tgz,flink-kubernetes-operator-1.7.0-src.tgz
new operator/delete operator就是new和delete操作符,而operator new/operator delete是函数。 new operator(1)调用operator new分配足够的空间,并调用相关对象的构造函数(2)不可以被重载 operator new(1)只...
operator-hub-redis-operator
安装calico网络组件(仅master节点),上传tigera-operator-3-26-1.yaml和custom-res
简述 C++ 中的 new 和 delete 的基本原理,并讲述了内存检测子系统的实现原理、实现中的技巧,并对内存泄漏检测的高级话题进行了讨论。解决了本人在内存泄露很多多问题(我也是down的别人的),觉得非常好,所以给...
mysql-operator-trunk
hbck2 工具类,hbase2.0后对工具进行分离出hbase client.
aerospike-operator-tools_0.12.0.tar
使用部署要创建运算符,可以直接使用kubectl创建它: kubectl create -f https://raw.githubusercontent.com/spotahome/redis-operator/master/example/operator/all-redis-operator-resources.yaml这将创建一个名为...
operator-overloading-js, JS简单运算符重载库 目录Operator-Overloading-JS安装工具node MODULE ( NPM )浏览器( Bower )Sneak示例重载运算符设计考虑/非常重要/必须阅读。Definig使用运算符重载的上下文
tidb-operator-crd.yaml
cluster-operator.yml
piraeus-operator-源码.rar
准备好opentelemetry-operator部署后,创建一个OpenTelemetry Collector(otelcol)实例,例如: $ kubectl apply -f - << EOF apiVersion: opentelemetry.io/v1alpha1 kind: OpenTelemetryCollector metada
C++_new_operator详解 C++_new_operator详解 C++_new_operator详解
从头开始初始化操作员代码 $ cd $GOPATH/src/github.com/onuryilmaz/$operator-sdk new k8s-operator-example --api-version=k8s.packt.com/v1 --kind=WeatherReport建立并推动 $ operator-sdk build onuryilmaz/k8s...