Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to have a static member variable in my templated class, without the class's user having to know about it?

I have a templated container class, something like this toy code:

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;
};

This class is really convenient to use -- any code can just #include "MyVector.h" and then start declaring objects of type MyVector and MyVector and so on, and it all Just Works (tm) without any futzing around required.

One thing that kind of bothers me, however, is the presence of the _defaultItem member variable, which is there solely to give GetFirstItemWithDefault() the ability to return a valid reference when the container is empty. The objection is that if I declare N MyVector objects, that means N copies of _defaultItem will be present in RAM as well --- even though they are all identical and read-only, and so there really only needs to be one of them per process, not one per MyVector.

So, the obvious solution is to make _defaultItem static .... but AFAICT that comes with a cost: if I do that, it is no longer possible for any old piece of code to simply #include "MyVector.h" and go... now the user has to be sure to declare storage for that static variable in one of his .cpp files, which is (a) a pain in the butt, and (b) means that the user of the code has to be aware of the details of the internal implementation of the class. Since _defaultItem is a private member variable, the user of the class shouldn't have to think about it or even realize it exists, let alone know that he needs to declare storage for it. (and what if two separate pieces of code both declare storage for it, each not knowing the other has done the same thing? Wouldn't that cause a duplicate-symbol linker error?)

Therefore, my question is: is there any way to tell C++ to automatically provide one unique storage (per instantiated type of MyVector) for this static member variable, so that users of MyVector don't have to know about it? (Note that it would need to be automatic for all possible instantiations of MyVector<...>, not just for a few common cases)

like image 596
Jeremy Friesner Avatar asked Jun 17 '11 05:06

Jeremy Friesner


People also ask

Is it possible to define a static member outside the class?

C++ The above program calls only B's constructor, it doesn't call A's constructor. The reason for this is simple, static members are only declared in a class declaration, not defined. They must be explicitly defined outside the class using the scope resolution operator.

Can a static member of a class be private?

Static member variables Such a member variable can be made private to a class, meaning that only member functions can access it.

How do you access the static member of a class?

We can access the static member function using the class name or class' objects. If the static member function accesses any non-static data member or non-static member function, it throws an error. Here, the class_name is the name of the class. function_name: The function name is the name of the static member function.

How do you use a static member variable?

Static Member Functions in C++ To create a static member function we need to use the static keyword while declaring the function. Since static member variables are class properties and not object properties, to access them we need to use the class name instead of the object name.


2 Answers

Why not make that default item static local to the function?

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

This may not be what you want if you want to check against the default item in some other function again, but for that you can just put it in a seperate function aswell (that may be static itself):

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

And call that function when you need to access the default item.


That said, I think having a default item isn't really nice. std::vector also doesn't have it and doesn't need it. Just tell the user to check if the vector is empty and be done. One problem with hidden statics is, that you don't know ItemType. It could be a class that eats tons of resources and you just made another instance of that! Maybe rethink that class' design and after that, switch to a std::vector. :)

like image 126
Xeo Avatar answered Sep 19 '22 00:09

Xeo


If it is a template, the compiler will do the magic for you. Just put the static member in the header, and the compiler will see to that it is just instantiated once.

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


template <class ItemType> 
const ItemType MyVector<ItemType>::_defaultItem;
like image 44
Bo Persson Avatar answered Sep 19 '22 00:09

Bo Persson