-1

I want to make a vector of objects, but I don't want to allocate them on the heap. I want to allocate them onto stack memory. But I'm running into issues.

struct Object { int x; Object(int x) { this->x = x; } };

int main() {
    std::vector<Object*> v;

    for (int i = 0; i < 5; i++) {
        Object o (i);
        v.push_back(&o);
        std::cout << &o << std::endl; // keeps printing the same mem address...
                                      // ...implying that these are all the same object
    }
}

I have a suspicion that the object is deleting itself after going out of scope after each iteration of the for-loop.

Now, I know that you can just do v.push_back(new Object(i)) for each iteration and it would work. However, I do not want these objects allocated onto the heap where I need to manually manage the memory.

Coffee Maker
  • 1,543
  • 1
  • 16
  • 29
  • 1
    `std::vector`? It's still going to be on the heap, but no management required. – T.C. Jul 06 '14 at 02:58
  • 1
    How about `std::vector >`? That way, you don't need to manually `delete` your objects. – user3553031 Jul 06 '14 at 03:00
  • 1
    There's [this](http://stackoverflow.com/questions/354442/looking-for-c-stl-like-vector-class-but-using-stack-storage), but really, `std::vector` if all you're concerned about is memory management. They're going on the heap anyway, but the point is that the vector manages them. – chris Jul 06 '14 at 03:00
  • Why do you want to allocate them on the stack? – Homer6 Jul 06 '14 at 03:21
  • Possible duplicate of http://stackoverflow.com/questions/354442/looking-for-c-stl-like-vector-class-but-using-stack-storage – Homer6 Jul 06 '14 at 03:25
  • @Homer6, I think there's a deeper answer than that. – chris Jul 06 '14 at 03:27
  • @chris Please elaborate. Also, there's a stack allocator referenced here: http://stackoverflow.com/a/23829781/278976 – Homer6 Jul 06 '14 at 03:32
  • 1
    @Homer6, Seems like an XY problem. The OP doesn't really want stack-allocated objects, just to not have to manage them manually. – chris Jul 06 '14 at 03:38
  • @chris In that case, I've added an answer below. The OP should change the question title if he really just wants managed memory as opposed to a stack allocator. – Homer6 Jul 06 '14 at 03:49

3 Answers3

2

You are basically correct that "object is [being destructed] after going out of scope". It's also confusing because of what you're printing. Based on how the compiler allocates the variables with "automatic storage duration" within the loop, the stack variable Object o always has the same address.

std::vector<Object*> v;
for (int i = 0; i < 5; i++) {
    Object o (i);
    v.push_back(&o);
    // Variable o still exists on the stack
    std::cout << &o << std::endl; // Prints the address of the automatic variable 'o'
}

// At this point, no objects exist; they all went out of scope
// every pointer in v is invalid, pointing to the "ghost" of a destoryed object.

I think the simpler approach you are looking for is to simply create a vector of objects.

std::vector<Object> v;

for (int i = 0; i < 5; i++) {
    v.push_back(Object(i));
    std::cout << &(v.back()) << std::endl; // Prints the address of the Object just added
}

That said, you should understand that the std::vector<Object> will manage your object lifetimes properly, destroying the objects when the vector itself goes out of scope. But the objects are actually stored on the free store. This is okay.

Here is the output from ideone when compiling and running with a vector of Objects:

0x8e66008
0x8e6601c
0x8e66030
0x8e66034
0x8e66050
NicholasM
  • 4,557
  • 1
  • 20
  • 47
  • For the simple struct referenced in the question, this is the ideal case. However, when you get into more elaborate classes (or objects with non-trival amounts of data), you'll want to use move semantics. – Homer6 Jul 06 '14 at 04:35
  • That's a good point. Fortunately, `push_back` [takes an rvalue reference](http://en.cppreference.com/w/cpp/container/vector/push_back), so the move constructor will be used when called as indicated. – NicholasM Jul 06 '14 at 04:42
  • What I meant by that is, if the object has dynamically allocated memory inside of it, you definitely should write the move constructor and move assignment operator (as opposed to just a copy constructor and copy assignment operator). In your case above, if this object didn't have a move constructor and a move assignment operator (and they were explicitly deleted), would it copy? – Homer6 Jul 06 '14 at 05:52
  • I would argue the ideal is to give your objects value semantics through resource-owning members (like smart pointers), and then to use the ["Rule of Zero"](http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html), rather than the class handling logic AND resource ownership. This avoids the situation you describe, by using compiler-generated move- and copy-constructors (if the copy constructors are well-formed). If a user really wants copying and not moving, and creates his/her class that way, is there a problem with the vector copying while pushing back? – NicholasM Jul 06 '14 at 16:55
0

If you really don't want to allocate them on the stack, but instead just want the memory managed, you really should take few hours to fill in some knowledge gaps.

In particular, picking up a good amount of knowledge on RAII is crucial to using C++ and C++11 effectively. I highly recommend The C++ Language Reference, 4th Edition. The 4th edition is important because it's very different from the the 3rd edition.

In it, it'll show you that will likely want to use std::vector<std::unique_ptr> for this particular problem, or to make Object a managed object itself (with move semantics implemented).

Homer6
  • 15,034
  • 11
  • 61
  • 81
-1

The vector is deleted, not the objects.

The following means that you save pointers in the vector v:

std::vector<Object*> v;

You could do this:

std::vector<Object> v;

in which case you get many objects, but then you get copies of your objects which at times is either not possible or not something you want (although newer version of the C++ compiler can do a move instead of a copy, but I don't think that would work in this case...)

Another way if you want the Objects to be allocated and then automatically deleted is to use a smart pointer.

#include <memory>
std::vector<std::shared_ptr<Object> > v;

In that case the Objects are allocated by you and freed whenever the vector gets deleted.

However, your problem is that you initialize objects on the stack and assign that stack pointer to your vector. I would image that your print shows you that the pointer is always the same... meaning that the previous object gets destroyed and a new one created on each iteration.

So I would replace these lines:

std::vector<Object*> v;

    Object o (i);
    v.push_back(&o);

By something like this:

std::vector<std::shared_ptr<Object> > v;

    std::shared<Object> o(new Object(i));
    v.push_back(o);

If you do not know anything about shared pointers, I suggest you read up on them. It's very useful whenever you allocate objects with new. Also there are a few traps with what is called circular references (i.e. check out weak_ptr as well). But in this way you do not have to manage memory and you have good pointers.

If you prefer the solution with the Object by itself, it would be something like this:

std::vector<Object> v;

    Object o(i);
    v.push_back(o);

This way you avoid the heap, however, you make copies each time you push_back (or a move). So if your objects are big, that's not a good idea.

Also, within your object, if you end up having pointers, using smart pointers will help you greatly too. So that's anyway a good idea to learn about them.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • 1
    Vectors can move elements around just fine as long as they have a `noexcept` move constructor. – chris Jul 06 '14 at 03:01
  • @chris, yeah... I guess in this case it would not matter because his object is currently very simple. But with time, it could still be benefit to avoid things like a shared pointer refcount incremented (copy) and then decremented (destructor). – Alexis Wilke Jul 06 '14 at 03:12