Effective C++ 2e Item13

条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同

顽固的Pascal和Ada程序员会经常想念那种可以任意设定数组下标上下限的功能,即,数组下标的范围可以设为10到20,不一定要是0到10。资深的C程序员会坚持一定要从0开始计数,但想个办法来满足那些还在用begin/end的人的这个要求也很容易,这只需要定义一个自己的Array类模板:

template<class T>
class Array {
public:
  Array(int lowBound, int highBound);
  ...

private:
  vector<T> data;               // 数组数据存储在vector对象中
                                // 关于vector模板参见条款49

  size_t size;                  // 数组中元素的数量

  int lBound, hBound;           // 下限,上限
};

template<class T>
Array<T>::Array(int lowBound, int highBound)
: size(highBound - lowBound + 1),
  lBound(lowBound), hBound(highBound),
  data(size)
{}

构造函数会对参数进行合法性检查,以保证highBound至少要大于等于lowBound,但这里有个很糟糕的错误:即使数组的上下限值合法,也绝对没人会知道data里会有多少个元素。

“这怎么可能?”我听见你在叫。“我小心地初始化了size后才把它传给vector的构造函数!”但不幸的是,你没有——你只是想这样做,但没遵守游戏规则:类成员是按照它们在类里被声明的顺序进行初始化的,和它们在成员初始化列表中列出的顺序没一点关系。用上面的Array模板生成的类里,data总会被首先初始化,然后是size, lBound和hBound。

看起来似乎有悖常理,但这么做是有理由的。看下面这种情况:

class Wacko {
public:
  Wacko(const char *s): s1(s), s2(0) {}
  Wacko(const Wacko& rhs): s2(rhs.s1), s1(0) {}

private:
  string s1, s2;
};

Wacko w1 = "Hello world!";
Wacko w2 = w1;

如果成员按它们在初始化列表上出现的顺序被初始化,那w1和w2中的数据成员被创建的顺序就会不同。我们知道,对一个对象的所有成员来说,它们的析构函数被调用的顺序总是和它们在构造函数里被创建的顺序相反。那么,如果允许上面的情况(即,成员按它们在初始化列表上出现的顺序被初始化)发生,编译器就要为每一个对象跟踪其成员初始化的顺序,以保证它们的析构函数以正确的顺序被调用。这会带来昂贵的开销。所以,为了避免这一开销,同一种类型的所有对象在创建(构造)和摧毁(析构)过程中对成员的处理顺序都是相同的,而不管成员在初始化列表中的顺序如何。

实际上,如果你深究一下的话,会发现只是非静态数据成员的初始化遵守以上规则。静态数据成员的行为有点象全局和名字空间对象,所以只会被初始化一次(详见条款47)。另外,基类数据成员总是在派生类数据成员之前被初始化,所以使用继承时,要把基类的初始化列在成员初始化列表的最前面。(如果使用多继承,基类被初始化的顺序和它们被派生类继承的顺序一致,它们在成员初始化列表中的顺序会被忽略。使用多继承有很多地方要考虑。条款43关于多继承应考虑哪些方面的问题提出了很多建议。)

基本的一条是:如果想弄清楚对象被初始化时到底是怎么做的,请确信你的初始化列表中成员列出的顺序和成员在类内声明的顺序一致。

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Effective C++》是由C++之父Bjarne Stroustrup所著的一本经典C++编程指南。这本书对于想要更深入理解和掌握C++编程的开发者来说是一本非常有用的资源。 《Effective C++》以52条编程规范的形式呈现,每一条规范都经过作者的亲身经历和经验总结。这些规范涵盖了C++中一些重要的概念、技术和最佳实践,从而帮助读者写出更高效、更健壮、更易维护的C++代码。 这本书主要分为多个部分,每个部分都聚焦于一个特定的主题。其中包括: 1. 构造/解构和赋值运算符重载:介绍了构造函数、析构函数、拷贝构造函数和赋值运算符的正确使用方式,避免内存泄漏和资源冲突。 2. 资源管理:提供了如何正确管理动态内存分配和资源使用的建议,包括智能指针、RAII等技术。 3. 类设计:讲解了类的设计原则和技巧,包括尽量使用const、规避对象切割等。 4. 继承与多态:介绍了如何正确使用继承和多态的技术,包括虚函数、多态对象的销毁等。 5. 异常安全:提供了如何处理异常以及避免资源泄漏的方法。 通过阅读《Effective C++》,读者可以学习到许多编写高质量C++代码的技巧和实践。作者结合自己在C++设计与开发中的丰富经验,以清晰的语言和易于理解的示例,帮助读者深入理解C++语言的特性和问题,并提供了解决方案。对于想要进一步掌握C++的开发者来说,这本书是一份不可或缺的参考资料。它不仅有助于提高代码质量,还能避免一些常见的陷阱和错误,从而使程序更加高效和可靠。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lostmouse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值