More Effective C++ 条款04:非必要不提供默认构造函数

2024-06-23 03:08

本文主要是介绍More Effective C++ 条款04:非必要不提供默认构造函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

所谓默认构造函数,就是不给任何变量,就可以给调用(无参或参数为默认值)。

基本准则:凡可以“合理地从无到有生成对象”的类,都应该包含默认构造函数,而“必须有某些外来信息才能生成对象”的类,则不必拥有默认构造函数。

但如果类缺乏一个默认构造函数,当你使用这个类时便会有某些限制。

考虑下面这个针对公司仪器而设计的class,在其中,仪器识别码是一定得有的一个构造参数:

class EquipmentPiece
{
public:EquipmentPiece(int ID);...
};

缺乏默认构造函数,其运行可能在3中情况下出问题。

1.产生数组的时候。一般而言没有任何方法可以为数组中对象指定构造参数,所以几乎不可能产生一个由EquipmentPiece对象组成的数组;

EquipmentPiece bestPieces[10]; //错误,无法调用EquipmentPiece 的构造函数
EquipmentPiece *bestPieces = new EquipmentPiece[10]; //错误,另有一些问题

有三种方法解决这个问题,第一个是使用不使用堆数组,于是能够在定义数组时提供必要的自变量:

int ID1,ID2,ID3...ID10; //变量,用来放置仪器识别码
EquipmentPiece best[] = {
EquipmentPiece(ID1),
EquipmentPiece(ID2),
EquipmentPiece(ID3),
EquipmentPiece(ID4),
....
EquipmentPiece(ID10),
};

缺点:不能增加数组长度。

第二个,更一般的做法是使用“指针数组”而非“对象数组”:

tyepdef EquipmentPiece* PEP; //PEP是指向EquipmentPiece的指针
PEP bestPieces[10]; //很好,不需要调用构造
PEP *bestPieces = new PEP[10]; //很好for(int i = 0; i < 10; ++i){bestPieces[i] = new EquipmentPiece(ID);
}

缺点有两个:1.必须记得将数组所指的所有对象删除,若忘了会内存泄漏。2.需要的内存总量变大,因为需要一些空间来放置指针,还有一些空间放置对象。

可以先为此数组分配内存,然后使用"placement new"在这块内存上构造对象。

//分配足够的内存,给一个预备容纳10个对象的数组使用
void *rawMemory = operator new[](10 * sizeof(EquipmentPiece));//让bestPieces指向此块内存,使这块内存被视为一个EquipmentPiece数组
EquipmentPiece *bestPieces = static_cast<EquipmentPiece*>(rawMemory);//利用placement new构造内存中的EquipmentPiece对象
for(int i = 0; i < 10; ++i){new (&bestPieces[i]) EquipmentPiece(ID);
}

placement new 缺点是程序员不熟悉,维护困难。此外你还得在数组内的对象结束生命时,以手动方式进行销毁,最后还得调用operator delete[] 方式释放内存。

//构造相反顺序析构
for(int i = 9; i >= 0; --i){bestPiece[i].~EquipmentPiece();
}//释放内存
operator delete[](rawMemory);

2.缺乏默认构造函数的第二个缺点是:它们将不适用于许多基础模板容器类,对那些template而言,被实例化的目标类型必须得有一个默认构造函数。

template<class T>
class Array
{
public:Array(int size);...
private:T *data;
};template<class T>
Array<T>::Array(int size)
{data = new T[size];  //数组中的每个元素都调用T::T()...
}

3.缺乏默认构造函数的第三个缺点是:虚基类如果没有默认构造函数,则要求其所有子类不论距离多么遥远,都必须知道、了解其意义,并且提供虚基类的构造参数。

总结:添加无意义的默认构造函数,也会影响类的效率。如果成员函数必须测试字段是否被初始化了,其调用者必须为测试行为付出时间代价,并为测试代码付出空间代价,因为可执行文件变大了。如果类构造函数可以确保对象的所有字段都会被正确地初始化,上述成本便可消除。如果默认构造函数无法提供这些保证,那么最好避免让默认构造出现。虽然这可能会对类的使用方式带来一些限制,但同时也带来一种保证:当你真的使用了这样的classes,你可以预期它们所产生的对象会被完全初始化。

这篇关于More Effective C++ 条款04:非必要不提供默认构造函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1086113

相关文章

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

详解C++中类的大小决定因数

《详解C++中类的大小决定因数》类的大小受多个因素影响,主要包括成员变量、对齐方式、继承关系、虚函数表等,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录1. 非静态数据成员示例:2. 数据对齐(Padding)示例:3. 虚函数(vtable 指针)示例:4. 继承普通继承虚继承5.

C++中std::distance使用方法示例

《C++中std::distance使用方法示例》std::distance是C++标准库中的一个函数,用于计算两个迭代器之间的距离,本文主要介绍了C++中std::distance使用方法示例,具... 目录语法使用方式解释示例输出:其他说明:总结std::distance&n编程bsp;是 C++ 标准

PyCharm如何设置新建文件默认为LF换行符

《PyCharm如何设置新建文件默认为LF换行符》:本文主要介绍PyCharm如何设置新建文件默认为LF换行符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录PyCharm设置新建文件默认为LF换行符设置换行符修改换行符总结PyCharm设置新建文件默认为LF

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa