6

在 Meeting C++ 2019 上,Jon Kalb 发表了关于模板技术的演讲并提到了策略类。见这里的来源:https ://youtu.be/MLV4IVc4SwI?t=1815

有问题的有趣代码片段是:

template<class T, class CheckingPolicy>
struct MyContainer : private CheckingPolicy
{
    ...
}

我经常看到这种类型的设计,我想知道这里的继承是否比组合有任何真正的优势。以我个人的经验,我听说过很多关于Prefer 组合优于继承范式的信息。所以我编写代码的方式会更像这样:

template<class T, class CheckingPolicy>
struct MyContainer
{
    CheckingPolicy policy;
    ...
}

不会涉及任何虚拟功能。不过,如果您能分享一些见解,我将不胜感激。我会对内存布局的差异及其影响特别感兴趣。如果CheckingPolicy没有数据成员,而只有一个check方法或一个重载的调用运算符,它会有所不同吗?

4

1 回答 1

4

一个可能的原因:当您从 继承时CheckingPolicy,您可以从空基类优化中受益。

如果CheckingPolicy(即,除了大小为 的位域0、没有虚函数、没有虚拟基类和非空基类之外,它没有非静态数据成员),它不会影响MyContainer.

相反,当它是 的数据成员时MyContainer,即使CheckingPolicy为空, 的大小MyContainer也会增加至少一个字节。至少,因为由于对齐要求,您可能会有额外的填充字节。

这就是为什么,例如,在实现中std::vector您可以从分配器中找到 ihnehritance。例如,libstdc++ 的实现

template<typename _Tp, typename _Alloc>
struct _Vector_base {
    typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
        rebind<_Tp>::other _Tp_alloc_type;

    struct _Vector_impl : public _Tp_alloc_type, public _Vector_impl_data { 
        // ...
    };

    // ...
};

无状态分配器(如CheckingPolicy没有非静态数据成员)不会影响std::vector的大小。

在 C++20 中,我们必须[[no_unique_address]]潜在地解决这个问题:而标准布局类型需要空基优化,[[no_unique_address]]这只是一种许可,而不是要求。(感谢Nicol Bolas指出这一点。)

于 2019-12-27T15:52:12.130 回答