03 October 2023

C++ 核心指南目录

“Do not mix hierarchies and arrays”

理由

一个派生类的数组,很容易隐式的衰变为指向基类的指针,这样会导致可怕的结果。

例子

假设 ApplePear 是两类水果 Fruit

void maul(Fruit* p)
{
    *p = Pear{};     // put a Pear into *p
    p[1] = Pear{};   // put a Pear into p[1]
}

Apple aa [] = { an_apple, another_apple };   // aa contains Apples (obviously!)

maul(aa);
Apple& a0 = &aa[0];   // a Pear?
Apple& a1 = &aa[1];   // a Pear?

很可能 aa[0] 还是个梨子( Pear )(无需类型转换!)如果 sizeof(Apple) != sizeof(Pear) 那么访问 aa[1] 就无法对其数组中的对象访问起点。我们遇到了类型不一致,可能会导致内存毁坏。永远不要写这样的代码。

注意, maul() 违反了 CppCoreGuidelines F.22 用 T* 或 owner<T*> 表示单个对象

替代方案

使用正确模板化的容器。

void maul2(Fruit* p)
{
    *p = Pear{};   // put a Pear into *p
}

vector<Apple> va = { an_apple, another_apple };   // va contains Apples (obviously!)

maul2(va);       // error: cannot convert a vector<Apple> to a Fruit*
maul2(&va[0]);   // you asked for it

Apple& a0 = &va[0];   // a Pear?

注意,这里 maul2() 中的复制操作违反了 CppCoreGuidelines ES.63 不要进行对象切片

强化

  • 一定要检测这些情况。