《More Effective C++》 4: 非必要不提供默认构造函数
在某个没有默认构造函数的类 class Object中,会在下面三种情况出现问题:
1、产生数组,由于在一般情况下,没有办法为数组提供构造函数的参数,因此,会出现各种问题。
#include <iostream>
using namespace std;
class Object
{
public:
Object(int ID)
{
//... ...
}
//... ...
};
int main()
{
Object objs[100]; //报错: 没有合适的默认构造函数可用
Object* objs = new Object[100]; //报错: 没有合适的默认构造函数可用
return 0;
}
《More Effective C++》提供了三种解决方案。
(1) 对于 non-heap 数组可以在定义数组时(heap数组不可用),改进:
Object objs[2] = {
Object(0),
Object(1)
};
(2) 比(1)更一般的做法是使用指针数组代替对象数组: Object* objs[10];
for (int i = 0; i < 10; i++)
{
objs[i] = new Object(i);
}
这个方法有两个缺点:其一是容易出现资源泄漏问题,其二就是,消耗内存空间较大。
(3) 先为数组分配raw memory,然后使用“placement new”在这块内存上构造需要的对象。
//分配足够的raw memory
void* rawMemory = operator new[](10 * sizeof(Object));
//让Object指针指向这段内存,这样就可以存储Object对象了
Object* objs = static_cast<Object*> (rawMemory);
//利用 placement new构造这块内存的Object对象
for (int i = 0; i < 10; i++)
{
// 《More Effective C++》条款8有提到new的这种使用方式。
new (&objs[i]) Object(i);
}
而对于上面那段空间的释放,也需要一定的技术的: //将Object对象按照与构造顺序相反的顺序析构。
for (int i = 9; i >= 0; i--)
{
objs[i].~Object();
}
//释放 rawmemory
operator delete[](rawMemory);
3.抽象基类如果缺乏默认 构造函数的话,其构造函数的参数将会来自遥远的子类,对于子类设计者来说,这是很恐怖的。
虽然没有默认构造函数会有以上的诸多不方便,但是,为了类的清晰度和效率,
《More Effective C++》建议,尽量不提供默认构造函数。