Can I have polymorphic containers with semantics in C ++ 11?

This is a continuation of a related post asking an eternal question:

Can I have polymorphic containers with semantics in C ++?

The question was asked somewhat incorrectly. It should have been more like:

Can I have basic type STL containers stored by value in which elements exhibit polymorphic behavior?

If you ask a question in C ++ terms, the answer is no. At some point, you will clip objects stored by value.

Now I ask the question again, but strictly in terms of C ++ 11. With changes in the language and standard libraries, is it now possible to store polymorphic objects by value in the STL container?

I am well aware of the possibility of storing a smart pointer to a base class in a container - this is not what I am looking for , as I am trying to build objects on the stack without using new .

Consider if you will (from a linked post) as a basic C ++ example:

 #include <iostream> using namespace std; class Parent { public: Parent() : parent_mem(1) {} virtual void write() { cout << "Parent: " << parent_mem << endl; } int parent_mem; }; class Child : public Parent { public: Child() : child_mem(2) { parent_mem = 2; } void write() { cout << "Child: " << parent_mem << ", " << child_mem << endl; } int child_mem; }; int main(int, char**) { // I can have a polymorphic container with pointer semantics vector<Parent*> pointerVec; pointerVec.push_back(new Parent()); pointerVec.push_back(new Child()); pointerVec[0]->write(); pointerVec[1]->write(); // Output: // // Parent: 1 // Child: 2, 2 // But I can't do it with value semantics vector<Parent> valueVec; valueVec.push_back(Parent()); valueVec.push_back(Child()); // gets turned into a Parent object :( valueVec[0].write(); valueVec[1].write(); // Output: // // Parent: 1 // Parent: 2 } 
+6
c ++ c ++ 11 stl
source share
3 answers

Just for fun, based on James commenting on a template-based system, I came up with this vector implementation. It misses a lot of functions and may be a mistake, but this is the beginning!

 #include <iostream> #include <vector> #include <boost/shared_ptr.hpp> template <typename T> class Vector { public: T &operator[] (int i) const { return p[i]->get(); } template <typename D> void push_back(D &x) { p.push_back(ptr_t(new DerivedNode<D>(x))); } private: class Node { public: virtual T &get() = 0; }; template <typename D> class DerivedNode : public Node { public: DerivedNode(D &x) : x(x) {} virtual D &get() { return x; } private: D x; }; typedef boost::shared_ptr<Node> ptr_t; std::vector<ptr_t> p; }; /////////////////////////////////////// class Parent { public: Parent() : parent_mem(1) {} virtual void write() const { std::cout << "Parent: " << parent_mem << std::endl; } int parent_mem; }; class Child : public Parent { public: Child() : child_mem(2) { parent_mem = 2; } void write() const { std::cout << "Child: " << parent_mem << ", " << child_mem << std::endl; } int child_mem; }; int main() { Vector<Parent> v; v.push_back(Parent()); v.push_back(Child()); v[0].write(); v[1].write(); } 
+4
source share

You, of course, cannot have a polymorphic array (or vector ). The requirement to store array elements adjacent to memory is fundamentally incompatible with the fact that different types of derived classes can have different sizes.

None of the standard library containers allow you to store objects of different types of derived classes in one container.

+8
source share

First of all, your requirements are still not entirely clear. I assume that you want "built-in storage" for the container; therefore, for example, in a "polymorphic" vector , all elements will be contiguous in memory (provided that only for proper alignment).

Now this is possible if you are ready to provide an exhaustive list of all the types that you intend to enter into the container at compile time. The simplest implementation would be to use the union of all possible types as the type of the base array, which would ensure sufficient size and proper alignment and the same O (1) access by index due to some space spent on elements of smaller types. I can go with this in more detail if you want.

If the list of types is known in advance, or if you do not want overhead, then you will have to maintain a separate pointer to pointers (or offsets from the beginning of the backup storage) to the elements, so that you can make O (1) access. Also, given alignment problems, I'm not sure if you can even do this in fully portable C ++ 03, although you definitely can in C ++ 0x.

+2
source share

All Articles