Is It Okay to Inherit Implementation from Stl Containers, Rather Than Delegate

Is it okay to inherit implementation from STL containers, rather than delegate?

The risk is deallocating through a pointer to the base class (delete, delete[], and potentially other deallocation methods). Since these classes (deque, map, string, etc.) don't have virtual dtors, it's impossible to clean them up properly with only a pointer to those classes:

struct BadExample : vector<int> {};
int main() {
vector<int>* p = new BadExample();
delete p; // this is Undefined Behavior
return 0;
}

That said, if you're willing to make sure you never accidentally do this, there's little major drawback to inheriting them—but in some cases that's a big if. Other drawbacks include clashing with implementation specifics and extensions (some of which may not use reserved identifiers) and dealing with bloated interfaces (string in particular). However, inheritance is intended in some cases, as container adapters like stack have a protected member c (the underlying container they adapt), and it's almost only accessible from a derived class instance.

Instead of either inheritance or composition, consider writing free functions which take either an iterator pair or a container reference, and operate on that. Practically all of <algorithm> is an example of this; and make_heap, pop_heap, and push_heap, in particular, are an example of using free functions instead of a domain-specific container.

So, use the container classes for your data types, and still call the free functions for your domain-specific logic. But you can still achieve some modularity using a typedef, which allows you to both simplify declaring them and provides a single point if part of them needs to change:

typedef std::deque<int, MyAllocator> Example;
// ...
Example c (42);
example_algorithm(c);
example_algorithm2(c.begin() + 5, c.end() - 5);
Example::iterator i; // nested types are especially easier

Notice the value_type and allocator can change without affecting later code using the typedef, and even the container can change from a deque to a vector.

Are STL containers designed to allow inheritance? [duplicate]

Are STL containers designed to allow inheritance or not?

Standard library containers allow Inheritance. Nothing stops you from inheriting from a standard library container class. You will not get any compilation errors if you do so.

But what they are not designed for is to allow is destruction of your derived class object through Base class pointer. So if you want to use inheritance for such a scenario(in short for dynamic polymorphism) then standard library containers are clearly not designed for it.

Is virtual destructor required for inheritance?

Base class destructor is only required to be virtual if you intend to call delete on base class pointer pointed to a derived class object. It will result in Undefined behavior if base class destructor is not virtual.

So to summarize, the rule is:

If you need inheritance for dynamic polymorphism standard library container classes are not designed for it, but If you don't need that you can safely inherit from them.

Note: Your analysis in the answer link you provided is correct. It just didn't get responses probably because the answer was posted long(a few years) after the original Q was posted. You have my +1 there now.

Inheriting from STL containers

If you have C++11 support, rather than inheritance you could do a templated using statement:

template <class T>
using custom_vector = std::vector<T, custom_allocator<T>>;

Then use your script to sed std::vector to custom_vector.

Extension of STL container through composition or free functions?

Hashing is an algorithm not a type, and probably shouldn't be restricted to data in any particular container type either. If you want to provide hashing, it probably makes the most sense to create a functor that computes a hash one element (int, as you've written things above) at a time, then use std::accumulate or std::for_each to apply that to a collection:

namespace whatever { 
struct hasher {
int current_hash;
public:
hasher() : current_hash(0x1234) {}

// incredibly simplistic hash: just XOR the values together.
operator()(int new_val) { current_hash ^= new_val; }
operator int() { return current_hash; }
};
}

int hash = std::for_each(coll.begin(), coll.end(), whatever::hasher());

Note that this allows coll to be a vector, or a deque or you can use a pair of istream_iterators to hash data in a file...

Proper way to extend the functionality of a container (like std::vector) in C++, without inheriting from it?

First, regarding …

“ I have repeatedly read that inheriting from STL containers is a Bad Thing.”

… with the reference providing the reason that STL containers do not have virtual destructors.

It's certainly good advice for novices to not derive from classes without virtual destructors. That makes them unable to e.g. access the protected member in std::stack, it makes them unable to use Microsoft COM technology, etc., but all in all, for the novice the net advantages are tremendous. Likewise we advice novices to not use raw arrays and direct new and delete, which when followed can be a tremendous net advantage for the novice, but still, some – more experienced – have to do it, have to implement the abstractions that the novices are (ideally) constrained to use, lest there be no dynamic allocation in any C++ program.

So, with classes like std::stack clearly demonstrating that an absolute rule about this is nonsense, the experienced programmer must weight the pros and cons, and when deciding on inheritance, must choose between public, protected and private inheritance.

Con public inheritance: if a novice allocates an auto_vector dynamically, and then attempts to destroy it by using delete on a pointer to std::vector, then the design has failed to guide the novice to correct usage. So if it is a goal to strongly guide novices to correct usage, then either don't do this, or also add functionality that makes dynamic allocation difficult for novices. E.g. add an operator new with additional argument of inaccessible type, or itself inaccessible.

For the case at hand other polymorphic access as std::vector is not a problem, because code that indexes a std::vector beyond its size already has Undefined Behavior.

For other cases, cases that one can imagine, that are different from the OP's case, one must consider the particulars of those other cases: general absolute rules don't cut it in programming (well, at least not in C++ programming).

Pro public inheritance in this case: it's, well, the easiest and most direct and clear expression of "I want all the base class' functionality".

Is C++ STL thread-safe for distinct containers (using STLport implementation)?

The SGI STL

The SGI STL is the grandmother of all of the other STL implementations.

See the SGI STL docs.

The SGI implementation of STL is
thread-safe only in the sense that
simultaneous accesses to distinct
containers are safe, and simultaneous
read accesses to to shared containers
are safe. If multiple threads access a
single container, and at least one
thread may potentially write, then the
user is responsible for ensuring
mutual exclusion between the threads
during the container accesses.

G++

libstdc++ docs

We currently use the SGI STL definition of thread safety.

STLPort

STLPort docs

Please refer to SGI site for detailed
document on thread safety. Basic
points are:

  • simultaneous read access to the same container from within separate
    threads is safe;
  • simultaneous access to distinct containers (not shared between
    threads) is safe;
  • user must provide synchronization for all accesses if
    any thread may modify shared
    container.

Are C++11 standard containers final?

The LWG discussed this issue at the recent meeting in Kona Feb. 6-10, 2012. This is LWG issue 2113.

The LWG decided to mark LWG 2113 as NAD (not a defect), with the rationale that the standard is already clear that existing classes such as containers and std::string can not be marked final by the implementation.

The discussion included the fact that while it may be frowned on to derive from such classes, it is clearly legal to do so in C++98/03. And making it illegal in C++11 would break far too much code.

Update

At this time, no library types in the current working draft are marked final.

Hiding STL container implementations from users of a class

Sometimes you have no choice, but to show the underlying container types. For example, for randomly accessed containers like std::vector v, I can do sort(v.begin(), v.begin()+10); whereas for a std::list li, I can only do li.sort(), how can you hide the container type, and only use iterators? These iterators are totally incompatible. Also, container type is one of the most fundamental consideration in software designing, why should you think about the future possibility of changing container type? That usually means bad designing, and total remake of the software.



Related Topics



Leave a reply



Submit