2

What is the right thing to do? I know that if the container is of base class value type, then derived object stored is 'sliced'. If container is of derived class type, then base class object can not be stored. Right?

If to go with pointers, auto_ptr can not be used because it's have copy semantic problem. Is shared_ptr the only solutions to handle this problem?

Could anyone provide more details, sample code or online articles that address this issue? It should be quite a common question however i did not find much information on it in textbook or online.

Thanks in advance.

btw, i just search on unique_ptr. It does not seem to support copy semantics. So isn't it only safe than auto_ptr to be used in STL, but maybe due to lack to copy semantics, many STL operation or algorithm can not be used on container of unique_ptr?

user1559625
  • 2,583
  • 5
  • 37
  • 75

4 Answers4

5

If you want polymorphic behavior (and you do want it), then you must use pointers or references. That is well documented in many places.

And since you cannot use containers of references, you have to use containers of pointers.

Now, you can use any type of pointer you see fit: unique_ptr, shared_ptr or raw pointers.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • 2
    It's true that you can't create a container of references. But you can fake it with `std::reference_wrapper`. It holds a pointer but lets you access it through a reference. – Pete Becker Sep 02 '12 at 10:47
  • Is there a way to know whether an algorithm can safely be used with `unique_ptr`? Obviously some can't (`copy()`, `fill()`) but it seems like some that just delete or rearrange elements might or might not, depending on how they're implemented. – j_random_hacker Sep 02 '12 at 12:40
  • 1
    @PeteBecker: I tried the container of `reference_wrapper` thing once and it didn't work so well. On problem is that in C++ you cannot overload the `operator.`, so in order to access to the members of the contained objects you will have to do, for example, `c[0].get()->member`. And if you have to do that, you could as well do `c[0]->member`. – rodrigo Sep 03 '12 at 08:18
2

The most obvious solution would be to use std::unique_ptr:

class IBase {};
class Derived : virtual public IBase {};
std::vector<std::unique_ptr<IBase>> v;
v.push_back(std::unique_ptr<IBase>(new Derived())); 

You could use std::shared_ptr, but it's ownership semantics significantly change the program's behaviour, keeping the dynamically allocated objects alive alive until nobody holds references to them.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Thanks juanchopanza, could you elaborate a little more on 'but it's ownership semantics significantly change the program's behaviour, keeping ...'? Do you mean using shared_ptr can sometimes leave unused copy around if programmer not very careful, so the object is not freed in-time; while unique_ptr has single copy always and does not have such problem? – user1559625 Sep 02 '12 at 11:32
  • @user1559625 [this SO question](http://stackoverflow.com/questions/6876751/differences-between-unique-ptr-and-shared-ptr) could help. Basically, a unique_ptr, has the ownership of the pointee and delets it when it gets deleted. Ownership can be "moved" from one unique_ptr to another, but there can never be more than one owner. With shared_ptr, there can be an arbitrary number of owners, and the last one to die deletes the pointee. Sometimes, you want to know exactly when a pointee gets deleted, other times you don't care. – juanchopanza Sep 02 '12 at 11:47
  • I think `IBase` must have a virtual destructor. With `shared_ptr` that is not an issue because of the type erasure of the deleter; but that's not the case with `unique_ptr`. – rodrigo Sep 03 '12 at 08:11
  • but then how do you get the original object back from that? – Ethan McTague Oct 01 '14 at 20:34
2

There is example with std::vector and std::shared_ptr. I think that's what you want.

#include <iostream>
#include <memory>
#include <vector>

class Base {
public:
   virtual void foo() {
      std::cout << "base" << std::endl;
   }
};

class Derived : public Base {
   void foo() {
      std::cout << "derived" << std::endl;
   }
};

int main()
{
   std::vector<std::shared_ptr<Base> > v;
   v.push_back(std::shared_ptr<Base>(new Base));
   v.push_back(std::shared_ptr<Base>(new Derived));

   for (auto it : v) {
      it->foo();
   }
}
fasked
  • 3,555
  • 1
  • 19
  • 36
0

[http://www.boost.org/doc/libs/1_51_0/libs/ptr_container/doc/ptr_container.html](The Boost pointer container library) is made just for this.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243