Advice on a better way to extend C++ STL container with user-defined methods

This is a bad idea.

There are a lot of reasons you shouldn't derive from STL classes, foremost of which is that they're not designed for it. Vector doesn't have a virtual destructor, so if you extend it, the superclass's destructor may not be called properly and you'll get memory leaks.

For more on this, see this answer on why not to derive from std::string. Many of the same points apply:

Constructor doesn’t work for class inherited from std::string

  • No virtual destructor
  • No protected functions (so you gain nothing by inheriting)
  • Polymorphism won't work, and you'll get object slicing. std::vector is assignable, but if you add your own fields they won't get copied on assignment if you assign from a vector pointer or vector reference. This is because vector's operator= does not know about your fields.

For all of these reasons, you're better off making utility functions than extending when it comes to STL.


why you need extend vector in this way?

use standard <algorithm> with your functors.
e.g.

std::min_element, std::max_element

int max_a = std::max_element
        ( 
            v.begin(), 
            v.end(), 
            boost::bind( 
                std::less< int >(),
                bind( &Item::a, _1 ), 
                bind( &Item::a, _2 ) 
            )
        )->a;

std::accumulate - for calculate avarage

const double avg_c = std::accumulate( v.begin(), v.end(), double( 0 ), boost::bind( Item::c, _1 ) ) / v.size(); // ofcourse check size before divide  

your ItemList::SpecialB() could be rewrited as:

int accumulate_func( int start_from, int result, const Item& item )
{
   if ( item.SpecialB() < start_from )
   {
       result -= item.SpecialB();
   }
   return result;
}

if ( v.empty() )
{
    throw sometghing( "empty vector" );
}
const int result = std::accumulate( v.begin(), v.end(), v.front(), boost::bind( &accumulate_func, v.front(), _1, _2 ) );

BTW: if you don't need access to members, you don't need inheritance.


Since you can only "extend" the vector by using its public interface, it is far more useful to write functions which operate on a vector instead of being part of a vector.

Heck, if you plan it well, make it work with iterators instead of indexes and it'll work with more than just std::vector (see <algorithm> for some very good examples).

For example, you could use a functor for the MaxA like this:

struct CmpA {
    bool operator()(const Item &item1, const Item &item2) { return item1.a < item2.a; }
}

const int result = std::max_element(v.begin(), v.end(), CmpA()).a;

your specialB could be just as simple with a functor and std::accumulate

EDIT: or for c++11 and later, it can be as simple as:

const int result = std::max_element(v.begin(), v.end(), [](const Item &item1, const Item &item2) {
    return item1.a < item2.a;
}).a;

EDIT: you've asked why it is better to do it this way:

if you use algorithms, templates and iterators, it'll work even if you decide to put the items in a std::list<Item> or whatever. It is simply more versitile and helps code reuseablity.

Plus the functions in <algorithm> do much of this for you so you can just use little 3 line adapter functors.

EDIT: In addition to this, tgamblin listed some very compelling reasons to not inherit from std::vector (and most other std containers, including std::string).