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
Is It a Good Idea to Typedef Pointers
What Are Rvalues, Lvalues, Xvalues, Glvalues, and Prvalues
How to Tokenize a String in C++
What Are Forward Declarations in C++
Why Do I Have to Access Template Base Class Members Through the This Pointer
Is Short-Circuiting Logical Operators Mandated? and Evaluation Order
Why Use Apparently Meaningless Do-While and If-Else Statements in Macros
Is There a Difference Between Copy Initialization and Direct Initialization
How to Print a Double Value With Full Precision Using Cout
Sorting a Vector of Custom Objects
Why Should I Prefer to Use Member Initialization Lists
How to Make My Custom Type to Work With "Range-Based For Loops"
Timer Function to Provide Time in Nano Seconds Using C++
Using G++ to Compile Multiple .Cpp and .H Files
Parsing a Comma-Delimited Std::String