这是在林锐的《高质量程序设计指南》中看到的,特此记录下。
1. plain new 普通new
void*operator new(std::size_t)throw(std::bad_alloc);
void operator delete( void *) throw();
该运算符在分配失败时将抛出异常,而非返回NULL。使用时要包含 <new>头文件。正常使用new,但要配以异常处理。如:
char *getMemory(unsigned long size)
{ char * p = new char[size];
return p; }
void main(void )
{ try{
char * p = getMemory(1000000);//可能发生异常
// ...
delete [ ] p;
}
catch(const std::bad_alloc & ex)
{ cout < <ex.what(); }
}
2.nothrow new 不抛掷异常new
void*operator new(std::size_t,const std::nothrow_t & )throw();
void operator delete( void *) throw();
该运算符在分配失败时不抛出异常,而是返回NULL。使用时要包含 <new>头文件。
该函数的第2形参是 struct nothrow_t { };它是个全局常对象 const nothrow_t nothrow; 用来作为 new 运算符的标志,以区别前一个new.
void func(unsinged long length)
{
unsinged char * p = new(nothrow) unsinged char[length];
//在使用这种new时要加(nothrow) ,明示不使用异常处理 。
if ( p == NULL) // 因不抛异常,故定要检查
cout < <“allocte failed !”;
// ...
delete [ ] p;
}
3.placement new 放置new
void*operator new(std::size_t ,void *);
void operator delete( void * ,void *);
该运算符是在已分配的内存上重新构造对象,因为不分配内存,所以不必担心分配失败。唯一的工作是调用构造函数。要包含 <new>头文件。
# include <new>
# include <iostream>
void main()
{ using namespace std;
char * p = new(nothrow) char [4];
if (p == NULL)
{ cout < <“allocte failed” < <endl; exit( -1 ); }
// ...
long * q = new(p)long(1000);
delete [ ]p; //只释放 p,不要用q释放。
}
p和q仅仅是首址相同,所构建的对象可以类型不同。所“放置”的空间应小于原空间,以防不测。当”放置new”超过了申请的范围,Debug版下会挂机,但Release版竟然能运行而不出错!
该运算符的作用是:只要第一次分配成功,不再担心分配失败。
# include <new>
# include <iostream>
void main()
{ using namespace std;
char * p = new(nothrow) char [100];
if (p == NULL)
{ cout < <“allocte failed” < <endl; exit( -1 ); }
long * q1 = new(p)long(100);
// 使用q1 ...
int * q2 = new(p) int[100/sizeof(int) ];
// 使用q2 ...
ADT * q3 = new(p) ADT[100/sizeof(ADT) ];
// 使用q3 然后释放对象 ...
delete [ ]p; //只释放空间,不再析构对象。
}
注意:使用该运算符构造的对象或数组,一定要显式调用析构函数,不可用delete代替析构,因为placement new 的对象的大小不再与原空间相同。
# include <new>
# include <iostream>
void main()
{ using namespace std;
char * p = new(nothrow) char [sizeof(ADT)+2];
if (p == NULL)
{ cout < <“allocte failed” < <endl; exit( -1 ); }
// ...
ADT * q = new(p) ADT;
// ...
// delete q; // 错误
q-> ADT::~ADT(); //显式调用析构函数,仅释放对象
delete [ ]p; //最后,再用原指针来释放内存.
}
placement new 的主要用途就是可以反复使用一块已申请成功的内存空间。这样可以避免申请失败的徒劳,又可以避免使用后的释放。
特别要注意的是对于 placement new 绝不可以调用的delete, 因为该new只是使用别人替它申请的地方(只是个租房户,不是房主。无权将房子卖掉)。释放内存是nothrow new的事,即要使用原来的指针释放内存.
分享到:
相关推荐
C++中运算符重载是指对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造。一般来说,重载的功能应当与原有功能相类似,不能...
### C++运算符的优先级和结合性 在C++编程语言中,了解运算符的优先级和结合性对于正确地编写和理解代码至关重要。本文将详细介绍C++中各种运算符的优先级及其结合性,并通过示例进行解释。 #### 一、运算符的...
4. 重载运算符:涉及到C++中运算符重载的规则和最佳实践,包括哪些运算符可以被重载、如何重载以及重载时应遵循的设计准则。 5. 模板和泛型编程:书中可能探讨了模板类和模板函数的设计和实现,以及如何编写与类型...
3. 运算符部分,讨论了C++中运算符的定义和使用注意事项: - ITEM M5警告程序员谨慎定义类型转换函数,因为它们可能导致意外的类型转换,引入难以发现的错误。 - ITEM M6阐述了自增和自减操作符前缀和后缀形式的...
在C++编程语言中,运算符重载是允许我们为已存在的运算符赋予新的含义或功能的一种机制。这个实例将探讨如何通过成员函数和非成员函数两种...通过练习和理解这些例子,你将更好地掌握C++中运算符重载和友元函数的使用。
- **运算符优先级**:讲解C++中运算符的优先级规则,避免因误用而产生的错误。 - **复合表达式**:解释复合表达式的使用场景和注意事项,确保代码逻辑清晰。 - **条件语句(if)**:介绍if语句的正确使用方法,包括...
- **运算符重载**:深入探讨C++中运算符重载的原理和实践,增强类的行为。 - **函数内联**:掌握内联函数的使用,以减少函数调用开销,但需注意内存消耗。 ### 8. **类的设计与实现** - **构造函数与析构函数**:...
- **运算符的优先级**:解释了C++中运算符的优先顺序。 - **复合表达式**:讲解了如何构建和使用复合表达式。 - **if语句**:详细讨论了条件语句的各种用法,包括布尔变量、整型变量、浮点变量、指针变量与零值比较...
- **运算符优先级**:了解C++中运算符的优先级顺序,避免意外的行为。 - **复合表达式**:复合表达式的使用应遵循一定的原则,确保代码的清晰度。 - **if语句**:条件判断的使用技巧,如避免过多嵌套、使用逻辑...
通过这个例子,我们可以学习到C++中运算符重载的基本原理和实践方法,这对于理解C++的面向对象特性及其在实际编程中的应用至关重要。同时,这也展示了如何通过自定义类型来增强语言的表达力,使得代码更符合数学上的...
- **运算符的优先级**:了解C/C++中运算符的优先级和结合性。 - **复合表达式**:如何合理地构建复合表达式以提高代码的可读性和效率。 - **if语句**:使用if语句时的最佳实践,避免常见的逻辑错误。 - **循环语句的...
- **运算符重载**:探讨C++中运算符重载的应用场景与限制。 - **函数内联**:分析内联函数的工作原理及其对性能的影响。 - **高级特性心得**:分享在实际开发中运用这些高级特性的心得体会。 ##### 第9章 类的构造...