0

I read other questions trying to figure this out but I didn't find much like what I have in mind. I'm kinda new to C++ and I just don't want to have my C++ code to look like "C with classes", or in other words, if there is a good "C++ way of doing this", that's what I'm looking for, but I'm a bit confused. Well, to the problem.

I have a class, say MyClass. Now, in other class, say MyContainer, I have a vector<MyClass> vec.

Let's say I'm now creating a method that populates a MyClass object with any arbitrary stuff and then pushes it into vec. First question is: should I allocate and push the object like the following? (using vector<MyClass> vec)

MyClass *obj = new MyClass(args);

vec.push_back(*obj);

I am not sure this is right, but by my understanding, this could make me avoid having to manually delete every instance of MyClass I put into vec when the instance of MyContainer is of no use anymore.

What bugs me is that, like I said, this does not seem right anyway, and the other way I can figure out is declaring vector<MyClass*> and writing:

MyClass *obj = new MyClass(args);

vec.push_back(obj);

But this would make me write a method to delete every instance of MyClass I created before, right?

So... What should I use and, if both are actually right, when one is preferrable to the other?

However, if everything is wrong from the start, how can I do this?

Thank yall!

PS: by the way, MyContainer is created in main(). I'm planning to use heap allocation. Should I?

Edit: I can't use C++11.

PS2: This is part of an assignment, but I found it general enough to be of use for anyone, not just me.

Giuliano
  • 172
  • 9
  • 1
    If you haven't done so already, it's worth reading up about RAII - "resource acquisition is initialisation" eg - [RAII and Smart Pointers](http://stackoverflow.com/questions/395123/raii-and-smart-pointers-in-c) Under this approach deletion automatically occurs in the destructor of a stack object. – sj0h May 14 '14 at 03:05

2 Answers2

4

You probably shouldn't use new unless you need the object to survive beyond the local scope of the variable.

Just declare it on the stack:

MyClass obj(args);
vec.push_back(obj);

In C++11, you can avoid any risk of extra copies of obj by using:

vec.emplace_back(args);
happydave
  • 7,127
  • 1
  • 26
  • 25
  • You mean, if I declare it on the stack, when I push the object is copied into the vector, so I don't have to worry about screwing everything when the function ends and we get out of its scope? – Giuliano May 14 '14 at 02:18
  • Right. Which means that in my first example, you'll technically have two copies of the object - the one on the stack, and the one in the vector. Which is why emplace_back is better, especially if the object is expensive to construct – happydave May 14 '14 at 02:20
  • I'm afraid I can't use C++11 (please see my edit and PS2 above). But I got it perfectly. Thank you. :) BTW: upvoted and marked as answer. – Giuliano May 14 '14 at 02:21
  • just on second thought, what if I want to return the pointer/reference to the object I just pushed? – Giuliano May 14 '14 at 02:23
  • 1
    Then you should return vec.back() – happydave May 14 '14 at 02:27
  • But @sbaker's point about polymorphism is a good one, and very important if you're trying to understand C++ – happydave May 14 '14 at 02:27
  • 1
    Be careful returning a reference (or iterator or pointer) to the object you just pushed as it could be invalidated by subsequent push_backs. If you know how big the vector will be at the start you can call resize first to guard against this. Or you can return an index into the vector instead. Or allocate on the heap and store pointers, preferably smart pointers. Even without C++11 you should have some flavour of shared_ptr available to you (e.g boost). It may even be worth constructing the vector with a size which will fill it with default constructed MyClass. – Chris Drew May 14 '14 at 04:59
4

Whether or not you should allocate on the heap or the stack as suggested by @happydave is highly dependent on the nature of "MyClass", IMO. If you need any kind of polymorphic behavior (i.e. you might have specialized subclasses of MyClass), then you should have a container of pointers.

If you're concerned about needing to delete each of the entries individually, there are two things that might help you:

1 . Use shared_ptr. So your code might look like this:

typedef std::shared_ptr<MyClass> MyClassPtr;

...

vector<MyClassPtr> vec;
vec.push_back(MyClassPtr(new MyClass());

The smart pointer will automatically delete MyClass when there are no more references to it.

2 . If you use bare pointers, you can still delete all the pointers with one line of code using std::for_each. This is described here: Can I call `delete` on a vector of pointers in C++ via for_each <algorithm>?

If you don't need polymorphic behavior and your class is copyable (either you gave it a copy constructor or the default copy is good for your implementation), then you can allocate on the stack.

Community
  • 1
  • 1
sbaker
  • 437
  • 2
  • 7
  • Got your point, and it answers a doubt raised the same way (polymorphism). But for this one time, this is not the case. – Giuliano May 14 '14 at 02:27