是否有可能在我的模板化类中有一个静态成员变量,而该类的用户不必知道它?

时间:2011-06-17 05:53:49

标签: c++ templates static member-variables

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

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类型的对象,等等,所有Just Works(tm)都没有任何需要的东西

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

因此,显而易见的解决方案是使_defaultItem成为静态....但AFAICT带有成本:如果我这样做,任何旧代码都不再可能只需#include“MyVector.h”然后...现在用户必须确保在他的一个.cpp文件中为该静态变量声明存储,这是(a)一个痛苦的屁股,(b)意味着代码的用户已经要了解班级内部实施的细节。由于_defaultItem是一个私有成员变量,因此该类的用户不应该考虑它,甚至不应该意识到它存在,更不用说知道他需要为它声明存储。 (如果两个独立的代码段都为它声明了存储,每个不知道另一个代码都做了同样的事情呢?这不会导致重复符号链接器错误吗?)

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

3 个答案:

答案 0 :(得分: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。 :)

答案 1 :(得分:3)

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

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


template <class ItemType> 
const ItemType MyVector<ItemType>::_defaultItem;

答案 2 :(得分:3)

  

所以,显而易见的解决方案是制作   _defaultItem static ....但AFAICT带有成本:如果我这样做,   任何旧的都不再可能   一段代码简单地#include   “MyArray.h”并且......现在用户已经拥有了   一定要申报存储   他的一个.cpp中的静态变量   文件,这是(a)痛苦

即可。这种担心是出于担忧。在template中,您可以(必须)在同一文件中声明static变量。

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

另请注意,只有在调用static时才会实例化此GetFirstItemWithDefault()成员。所以不要担心冗余分配。

唯一担心的是为所有ItemType提供默认构造函数,因为static对象通常会依赖于默认构造函数(您必须关注它) , 我猜)。就是这样。