0

“空成员”C++ 优化中是以下代码片段:

// Listing 4: A Better Way to Eliminate Bloat

template <class T, class Alloc = allocator<T> >
class list {
  . . .
  struct Node { . . . };
  struct P : public Alloc {
    P(Alloc const& a) : Alloc(a), p(0) { }
    Node* p; // Why also encapsulate a Node pointer?
  };
  P head_;

 public:
  explicit list(Alloc const& a = Alloc())
    : head_(a) { . . . }
  . . .
};

此实现的目的主要是避免在Alloc类没有数据成员(如在默认allocator类中)的情况下对象膨胀,但此特定实现的一个重要的值得注意的好处是防止(任意)Alloc类和班的成员list

代码片段下方的注释通过说明以下内容总结了这一点:

现在,list<> 成员通过说“head_.allocate()”来获取存储空间,并通过说“head_.p”来提及第一个列表元素。这非常有效,没有任何不必要的开销,并且 list<> 的用户无法区分。

我理解这条评论的第一部分,即P类内的接口封装,以便list<>成员必须调用head_.allocate()才能获取存储。

但是,我不理解此评论的第二部分 - 为什么有必要(或有益)Node在类中包含一个指针,P以便成员通过说(而不是直接成为成员)来list<>提及第一个列表元素?这与封装类的接口有关吗?head_.pplist<>Alloc

为什么封装接口的嵌套类有一个指向 a 的指针Node,而不是顶级类?

4

2 回答 2

2

在这种情况下,sizeof(list)将是sizeof(P),而希望是sizeof(Node*)。如果Alloc类型为空,则其空间使用将被优化掉。

现在考虑以下替代方案。

class list {
  struct Node { . . . };
  struct P : public Alloc {
    P(Alloc const& a) : Alloc(a), p(0) { }
  };
  Node* head_pointer;
  P thing_with_allocator;
}

在这种情况下,sizeof(list)sizeof(Node*) + sizeof(P). 空基类优化在这里并没有真正的帮助,因为即使P现在是一个空类,它也不会被用作基类,所以它不能受到空基类优化:它的大小至少为 1。

于 2013-03-23T20:18:01.223 回答
1

你的替代方案是什么?

class list {
    struct P : public Alloc {
        P(Alloc const& a) : Alloc(a), p(0) { }
    };
    P a;
    Node* h;
    ...
};

那么您将不会保存任何内容,因为您必须实例化一个可能为零大小的P对象。这将占用列表对象中的至少一个字节。

于 2013-03-23T20:15:39.170 回答