7

我有一个模板化的容器类,类似于这个玩具代码:

template <class ItemType> class MyVector
{
public:
   MyVector() : _numItems(0), _items(NULL) {/* empty */}

   /** Returns a reference to the first item in our array,
     * or a default-constructed item if the array is empty.
     */
   const ItemType & GetFirstItemWithDefault() const
   {
      return (_numItems > 0) ? _items[0] : _defaultItem;
   }

   [other methods omitted because they aren't relevant]

private:
   int _numItems;       // how many valid items (_items) points to
   ItemType * _items;   // demand-allocated
   const ItemType _defaultItem;
};

这个类使用起来真的很方便——任何代码都可以只 #include "MyVector.h" 然后开始声明 MyVector 和 MyVector 类型的对象等等,这一切都只是工作(tm),不需要任何麻烦。

然而,让我感到困扰的一件事是 _defaultItem 成员变量的存在,它只是为了让 GetFirstItemWithDefault() 能够在容器为空时返回有效引用。反对意见是,如果我声明 N 个 MyVector 对象,这意味着 _defaultItem 的 N 个副本也将存在于 RAM 中 --- 即使它们都是相同的并且是只读的,因此实际上只需要其中一个过程,而不是每个 MyVector 一个。

因此,显而易见的解决方案是将 _defaultItem 设为静态 .... 但 AFAICT 会带来成本:如果我这样做,任何旧代码都不再可能简单地 #include "MyVector.h" 就可以了。 .. 现在用户必须确保在他的一个 .cpp 文件中声明该静态变量的存储,这是 (a) 令人头疼的问题,并且 (b) 意味着代码的用户必须意识到类的内部实现的细节。由于 _defaultItem 是一个私有成员变量,该类的用户不应该考虑它甚至意识到它的存在,更不用说他需要为它声明存储。(如果两段单独的代码都为它声明存储,每个都不知道对方做了同样的事情怎么办?这不会导致重复符号链接器错误吗?)

因此,我的问题是:有没有办法告诉 C++ 自动为这个静态成员变量提供一个唯一的存储(每个 MyVector 的实例化类型),以便 MyVector 的用户不必知道它?(请注意,对于 MyVector<...> 的所有可能实例化,它需要是自动的,而不仅仅是一些常见情况)

4

3 回答 3

8

为什么不将该默认项设为函数的本地静态项?

const ItemType & GetFirstItemWithDefault() const
{
    static const ItemType _default;
    return (_numItems > 0) ? _items[0] : _default;
}

如果您想再次检查其他函数中的默认项,这可能不是您想要的,但为此您也可以将它放在一个单独的函数中(它本身可能是静态的):

static const ItemType& GetDefault() const
{
  static const ItemType _default;
  return _default;
}

并在您需要访问默认项时调用该函数。


也就是说,我认为拥有默认项目并不是很好。std::vector也没有它,也不需要它。只需告诉用户检查向量是否empty已完成。隐藏静力学的一个问题是,你不知道ItemType。它可能是一个消耗大量资源的类,而您刚刚创建了另一个实例!也许重新考虑该类的设计,然后切换到std::vector. :)

于 2011-06-17T05:57:11.077 回答
3

如果它是一个模板,编译器会为你做魔法。只需将静态成员放在头文件中,编译器就会看到它只是实例化一次。

template <class ItemType> 
class MyVector
{
public:
    //...
private:
    static const ItemType _defaultItem;
}; 


template <class ItemType> 
const ItemType MyVector<ItemType>::_defaultItem;
于 2011-06-17T06:38:11.053 回答
3

因此,显而易见的解决方案是使 _defaultItem 成为静态 .... 但 AFAICT 需要付出代价:如果我这样做,任何旧代码都不再可能只是简单地 #include "MyArray.h" 就可以了。 .. 现在用户必须确保在他的一个 .cpp 文件中声明该静态变量的存储,这是 (a) 一个痛苦

没有。这种恐惧是出于担心。在templates 中,您可以(必须)static在同一个文件中声明变量。

template <class ItemType> class MyVector
{
  const ItemType _defaultItem;
};
template <class ItemType>
const ItemType MyVector<ItemType>::_defaultItem; // ok (no multiple symbols)

另外,请注意,该成员仅在被调用static时才会被实例化。GetFirstItemWithDefault()所以也不必担心冗余分配。

The only thing worry is to provide default constructor to all the ItemType as the static object will generically rely on the default constructor (which you must be caring about already, I guess). That's it.

于 2011-06-17T06:51:53.990 回答