More Effective C++:Item 27
2015-08-08 16:26
489 查看
温习More Effective C++,对于Item 27:要求或禁止在堆中产生对象,整理思路于此文。
下表列出了不同位置上不同形式的对象定义所需函数的最低访问权限。
注意:
通过提供伪构造函数可以让指针对象摆脱对class operator new和构造函数的依赖。
不存在非堆对象的指针成员形式。
基类对象的class operator new不是必需的,因为派生类可以重载该函数。
成员对象的class operator new不是必需的,因为整体类不需要调用它。
结论:
独立形式: 通过声明class operator new为private可以禁止对象定义在堆上,如果声明构造函数为private并提供伪构造函数就可以限制对象定义再堆上。
指针成员形式:
直接成员形式和基类形式:定义条件完全相同,无法限制。
然而对于成员对象和基类对象却又不存在什么好的办法,因为只有定义了public构造和析构函数,它们才能被定义在非堆位置,然而这也会使得它们能被定义在堆中。同样的,若是将构造或析构函数定义为private,那么它们的定义将会被完全禁止。
然后,即使是对于独立对象,它也不怎么好用,具体请参考More Effective C++ Item27。
1. 要求独立对象和成员对象在堆中。
2. 禁止独立对象在对象。
编译期控制
通过禁用定义对象所需的条件,以在编译期阻止对象的定义。下表列出了不同位置上不同形式的对象定义所需函数的最低访问权限。
class operator new | 构造函数 | ←堆内对象 堆外对象→ | 构造函数 | class operator new | ||
public | public | 独立形式 | public | private | ||
private | public | 直接成员形式 | public | private | ||
public | public | 指针成员形式 | — | — | ||
private | protected | 基类形式 | protected | private |
通过提供伪构造函数可以让指针对象摆脱对class operator new和构造函数的依赖。
不存在非堆对象的指针成员形式。
基类对象的class operator new不是必需的,因为派生类可以重载该函数。
成员对象的class operator new不是必需的,因为整体类不需要调用它。
结论:
独立形式: 通过声明class operator new为private可以禁止对象定义在堆上,如果声明构造函数为private并提供伪构造函数就可以限制对象定义再堆上。
指针成员形式:
直接成员形式和基类形式:定义条件完全相同,无法限制。
// 数字类。 class Number { public: // 提供伪构造函数。 static Number* MakeInstance() { return new Number; } virtual ~Number() {} protected: // 将构造函数声明为protected。 Number() {} }; //============================================================================== // 独立对象。 //============================================================================== void DefineIndependentObject() { //========================================================================== // 定义在堆中:正确。 //========================================================================== Number* heapObject = Number::MakeInstance(); delete heapObject; //========================================================================== // 定义在栈中:错误。 //========================================================================== Number nonheapObject; } //============================================================================== // 成员对象。 //============================================================================== void DefineMemberObject() { //========================================================================== // 定义在堆中:正确。 //========================================================================== { // 财产类包含一个数字类指针。 class Asset { public: Asset() : value( Number::MakeInstance() ) {} ~Asset() { delete value; } private: Number* value; }; Asset* heapObject = new Asset; delete heapObject; } //========================================================================== // 定义在栈中:错误。 //========================================================================== { // 财产类包含一个数字类。 class Asset { private: Number value; }; Asset nonheapObject; } } //============================================================================== // 子类对象 //============================================================================== void DefineSubclassObject() { // 负数类派生自数字类。 class NegativeNumber : public Number {}; //========================================================================== // 定义在堆中:正确。 //========================================================================== NegativeNumber* heapObject = new NegativeNumber; delete heapObject; //========================================================================== // 定义在栈中:正确。 //========================================================================== NegativeNumber nonheapObject; }
禁止对象在堆中
只需禁用public class new即可禁止独立对象定义在堆中,并且不会对其在非堆位置中的定义产生影响。然而对于成员对象和基类对象却又不存在什么好的办法,因为只有定义了public构造和析构函数,它们才能被定义在非堆位置,然而这也会使得它们能被定义在堆中。同样的,若是将构造或析构函数定义为private,那么它们的定义将会被完全禁止。
#include <new> class Number { private: static void* operator new( std::size_t ) throw() { return nullptr; } }; //============================================================================== // 独立对象。 //============================================================================== void DefineIndependentObject() { //========================================================================== // 定义在堆中:错误。 //========================================================================== Number* heapObject = new Number; delete heapObject; //========================================================================== // 定义在栈中:正确。 //========================================================================== Number nonheapObject; }
运行期控制
通过堆对象和非堆对象的不同创建流程来进行控制。其不同之处只有一点:创建堆对象时class operator new会被调用。然而,首先,这一点只对独立对象管用:基类堆对象和成员堆对象的class operator new不一定被调用。#include <new> #include <iostream> class Number { public: static void* operator new( std::size_t ) throw() { std::cout << "class operator new for Number" << std::endl; } }; class NegativeNumber : public Number { public: static void* operator new( std::size_t ) throw() { std::cout << "class operator new for NegativeNumber" << std::endl; } }; class Asset { Number value; }; int main() { // 独立堆对象的class operator new被调用。 Number* independentObject = new Number; delete independentObject; // 看,基类堆对象的则没有被调用。 NegativeNumber* baseObject = new NegativeNumber; delete baseObject; // 看,子类堆对象的也没有被调用。 Asset* memberObject = new Asset; delete memberObject; return 0; }
然后,即使是对于独立对象,它也不怎么好用,具体请参考More Effective C++ Item27。
总结
控制对象的内存位置比较困难,能够完美实现的只有:1. 要求独立对象和成员对象在堆中。
2. 禁止独立对象在对象。
相关文章推荐
- C语言中关于.h文件和.c文件详细解析
- 部分华为校园招聘机试试题及答案(C语言版本)
- 一起talk C栗子吧(第三十二回:C语言实例--再谈最大公约数)
- C++ STL遍历map的时候如何删除其中的element
- #转 c语言中.h文件的作用
- #转 c语言中.h文件的作用
- C语言中的类型提升——基础概念,但还有很多人搞不清
- C语言5种程序语句(2)——函数语句
- C++_友元函数
- C++内存对象大会战
- 【C语言】把从1到1000的数打印出来,但你不能使用任何的循环语句或是条件语句。
- 剑指offer刷题之c++实现的树的子结构
- C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)
- 【C语言】冒泡排序与回文判断
- 【C语言】在终端输入多行信息,找出包含“ould”的行,并打印改行。
- C++使用CInternetSession请求url下载jason数据,并且进行解析。以及注意事项
- 【C语言】学生成绩链表的录入
- 指针函数与函数指针的区别
- C语言结构体学习系列之(二)
- c语言time.h函数库小结