0

I'm trying to save an object of X class, which is derivated from a base class Y in a std::list<Y>. X class has stuff that Y class doesn't has, and when I save the object the std::list, object slicing happens. There are more, different classes that use Y as a base, so for simplicity, using just one storage would be ideal, the thing is that they have different members, so using static_cast didn't work as expected. Is there a workaround to this problem? Or should I just give it up and use different containers for each type?

  • 1
    `X` is derived from `Y`? You're really just trying to mess with everyone's heads, aren't you. Like `Foo & operator++(); // decrements Foo`. – Kerrek SB Apr 09 '15 at 21:44
  • I wish that it would be just to mess with people. `X` is indeed derived from `Y` –  Apr 09 '15 at 21:47
  • 1
    @TahOmegaFire well even if in your code `X` is derived from `Y`, you can still ask the question differently, with `X` replaced by `Y` and viceversa. This way, only you may be the one a bit messed up, but all other people will understand the question faster. – vsoftco Apr 09 '15 at 22:33

2 Answers2

0

Keep a list of Y*. Then you have full virtual function resolution at your disposal and, if needed, you can dynamic_cast (although I would advise against that).

The reason for the latter being that there usually is a reason why you keep a list-of-Y's in stead of something else.

emvee
  • 4,371
  • 23
  • 23
0

Slicing happens because you effectively copy the elements in the list (by value). Use a

std::list<std::unique_ptr<Y>> 

or, in case you need shared ownership,

std::list<std::shared_ptr<Y>> 

instead (and better swap the names X and Y, as usually Y is derived from X).

In case you don't need shared ownership, you should use a std::unique_ptr, in that case making sure that you std::move your elements in and out of the list. std::unique_ptr doesn't have the overhead of std::shared_ptr (no reference counting), being effectively as fast/small as a raw pointer.

Community
  • 1
  • 1
vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • Why not `std::list>`? That's a genuine solution. Your code does a lot more, at a greater cost. – Kerrek SB Apr 09 '15 at 21:45
  • @KerrekSB I just wanted to make an additional edit about `std::unique_ptr`. You may not always want to move in the list though. – vsoftco Apr 09 '15 at 21:46
  • You cannot duplicate derived objects if all you have is a base subobject, so that's a non-issue. (If you had a cloning mechanism, you could use a suitable `value_ptr` or `clone_ptr`.) I'd consider the (almost accidental?) aliasing that the shared pointer would introduce a far greater disaster. – Kerrek SB Apr 09 '15 at 21:48
  • @KerrekSB let me think a bit about it and will edit after, thanks for the comment – vsoftco Apr 09 '15 at 21:49
  • In other words, your proposed solution is a race condition waiting to happen, or a bug that will cost you (or more likely your replacement) a whole christmas break to find :-) – Kerrek SB Apr 09 '15 at 21:53
  • (I saw your code post. Let me repeat that if you are trying to copy an object of a polymorphic type, you have a problem with your design. Copying is for value types, which is in some sense the exact opposite of a polymorphic type.) In my opinion, your example is contrived and doesn't constitute an argument. – Kerrek SB Apr 09 '15 at 22:08
  • @KerrekSB OK, I was thinking more about http://ideone.com/jNB9ws (shared_ptr) vs http://ideone.com/FfnWPk (unique_ptr) Ignore the first snippet in my deleted comment. I meant exactly the difference between these 2 code snippets, one using `unique_ptr` and one `shared_ptr`. You may want to push pointers but increase the reference count. Maybe the example is artificial, but that's what I initially had in mind. – vsoftco Apr 09 '15 at 22:08
  • @KerrekSB and aside from the additional memory allocated for the ref. counting, I think the other down performance is the reference counting itself (which afaik) is atomic (hence slow), but again, it depends (imo) on what your requirements are. – vsoftco Apr 09 '15 at 22:26
  • Yes, but really performance is secondary to sanity of concept. You need to keep a clear head around the concepts of sharing, aliasing and polymorphism, and which of those is necessary to model your problem. Unfortunately you can only rarely program C++ by recipe, and my main point was to avoid sneaking in such a wealth of conceptual baggage through the back door of a "just do this" recipe. The simple recipe is to use a unique pointer; if that doesn't work, then you are already in a situation where you need to program intelligently rather than by following recipes. – Kerrek SB Apr 09 '15 at 22:29
  • @KerrekSB Thanks, I see your point, and actually edited the code before, putting the `unique_ptr` solution first, as it is indeed probably enough in OP's case. I don't really understand what you meant by aliasing though... like `shared_ptr` pointing via another `shared_ptr` to itself and leaking at the end? – vsoftco Apr 09 '15 at 22:30