Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does it make sense to inherit from STL containers and delete `new` operators to prevent undefined behavior because of lacking virtual destructors?

I was told on this forum, I have read it in the books, and there are other answers stating that it is never good to inherit STL containers, because of the STL container destructors are not virtual (undefined behavior when deleting a derived object via base class pointer).

However, the C++11 standard now allows a design-by-contract checking at compile time, with member function specifiers, like delete. I can fully understand why inheriting an STL container with a goal to extend with one member function or two is better replaced with coding the member functions as algorithms. Still, I have a situation where I model a collection of elements as a Concept, and the elements themselves are containers of other elements. I need to implement bidirectional iterators that access sub-element data Forward Iterator (e.g. Collection::sub_element_iterator). Using composition forces me in this case, to re-type (adapt) the entire std::vector public interface, only to extend this new Collection with an iterator.

Is in this scenario o.k if I still use inheritance, and prevent heap allocation in the following way?

Here is a small model of this:

#include <vector>

class not_heap_allocable
{
    public: 
        void* operator new  (std::size_t count) = delete;
};

template
<
    typename Type,
    template <typename T> class Allocator = std::allocator
>
class extended_vector
:
    public std::vector<Type, Allocator<Type>>, 
    public not_heap_allocable
{
    public: 
        typedef std::vector<Type> BaseType; 

        using BaseType::BaseType; 
};

using namespace std;

int main(int argc, const char *argv[])
{

    vector<int>* vNew = new extended_vector<int> ({0,1,2,3,4,5});  // Compile time error. 

    return 0;
}

Which then results in a compile-time error:

main.cpp: In function ‘int main(int, const char**)’:
main.cpp:31:64: error: use of deleted function ‘static void* not_heap_allocable::operator new(std::size_t)’
     vector<int>* vNew = new extended_vector<int> ({0,1,2,3,4,5});  // Compile time error. 
                                                                ^
main.cpp:6:15: error: declared here
         void* operator new  (std::size_t count) = delete;

As a result, the extended_vector is no longer counting on humans not to misuse it.

like image 713
tmaric Avatar asked Dec 30 '25 20:12

tmaric


1 Answers

This approach seems more complicated and possibly less clear than inheriting protected and then using (into public) the base class members your child class actually needs to expose. That prevents all the problems of publicly inheriting in such a way while not introducing any unexpected concerns by probiting new.

EDIT: I found what I was looking for from boost: This SO question Writing an iterator that makes several containers look as one which links to boost::join http://www.boost.org/doc/libs/1_46_1/libs/range/doc/html/range/reference/utilities/join.html which lets you join multiple ranges into one.

like image 70
Mark B Avatar answered Jan 01 '26 11:01

Mark B



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!