How to Name a Vector in C++

I needed a named vector for my work in the Stock Market Analysis Library.

I'll lead with the answer:

class named_vector : public vector <double>
{
public:
    string name;
};

And it's used as follows:

using namespace std;
int f ()
{
    named_vector x;
 
    x.push_back (17.);
    x.push_back (7.);
    x.push_back (67.);
    x.name = "spud";
    sort (x.begin(), x.end());
    cout << "A vector named " << x.name << " contains: ";
    for (auto i : x) cout << i << " "; cout << "\n";
}

C++ experts will go, “yeah, so?” — but believe it or not, this represents a significant “Aha! I get it!” moment.

In my mind, the problem is the way that I think about what I'm trying to do. Coming from a C background, I'm not thinking about hierarchies and inheritence, and all that good stuff that the texts teach (you know, the whole “Apples and Oranges are Fruits,” and “a Line is a Shape and a Circle is a Shape” type of thing).

My use case is simply “I want to create a new object that associates a name with a vector.” All I'm doing (in my mind) is making a new class that combines a string and a vector <double>.

Unfortunately, that line of thinking leads to code like the following:

class named_vector
{
public:
    string name;
    vector <double> values;
};

Which is more complicated than it needs to be, and means that I have to treat the value contained within the vector specially (I need to access it by name within the object), and so on.

But it doesn't obviously lead to “I need to build a class hierarchy.”

Even the TL;DR crowd will appreciate that the template version of the named vector (done the right way) isn't that much more complicated:

template <typename T>
class named_vector : public vector <T>
{
public:
    string name;
};

And it's used as you would suspect:

named_vector <double> x;

Constructors

What about constructors, you ask? Well, C++11 has this amazing ability to inherit constructors from the base class. All we need to do is add an extra parameter for the name:

template <typename T>
class named_vector : public vector <T>
{
public:
    using vector<T>::vector;  // inherit constructor
    template named_vector(string _name = "", int n = 0, int value = 0)
    : vector<T> (n, value), name (_name) {}
    string name;
};

Which we can use in the obvious manner:

named_vector <int> z; // no name, no elements
named_vector <int> ("vector of integers, zero size");
named_vector <double> ("vector of double, 11 elements default initializer", 11);
named_vector <char> ("vector of char, 7 elements initialized to 52", 7, 52);

Controversy

You wouldn't believe the controversy this has caused! I shared this post on LinkedIn and got a wide variety of responses.

They ranged from “cool!” to “don't do that!” and all the way in between.

To summarize, the main problem that people have with this is that the vector's destructor is not virtual, meaning that you will get a memory leak. You will also get slicing if you try to do anything clever with the base class.

Distancing slightly from the “just don't do it” crowd, it seems to be a case of “if you know what you're doing, and prepared for the consequences...” kind of thing. One suggestion was to simply declare the frankenvector as final so that nobody can use it as a base class.

In general, the concensus seemed to be “prefer composition over inheritance.”

It's certainly been a learning experience :-)