tags:

views:

454

answers:

11

Below, I'm not declaring my_ints as a pointer. I don't know where the memory will be allocated. Please educate me here!

#include <iostream>
#include <vector>

class FieldStorage
{
private:
    std::vector<int> my_ints;

public:
    FieldStorage()
    {
        my_ints.push_back(1);
        my_ints.push_back(2);
    }

    void displayAll()
    {
        for (int i = 0; i < my_ints.size(); i++)
        {
            std::cout << my_ints[i] << std::endl;
        }
    }
};

And in here, I'm declaring the field my_ints as a pointer:

#include <iostream>
#include <vector>

class FieldStorage
{
private:
    std::vector<int> *my_ints;

public:
    FieldStorage()
    {
        my_ints = new std::vector<int>();
        my_ints->push_back(1);
        my_ints->push_back(2);
    }

    void displayAll()
    {
        for (int i = 0; i < my_ints->size(); i++)
        {
            std::cout << (*my_ints)[i] << std::endl;
        }
    }

    ~FieldStorage()
    {
        delete my_ints;
    }
};

main() function to test:

int main()
{
    FieldStorage obj;
    obj.displayAll();
    return 0;
}

Both of them produces the same result. What's the difference?

+4  A: 

You have to release ( to prevent memory leak ) memory allocated for vector in the second case in the FieldStorage destructor.

FieldStorage::~FieldStorage()
{
    delete my_ints;
}
Mykola Golubyev
+1. Or better yet, use a smart pointer such as std::auto_ptr, boost::scoped_ptr, or boost::shared_ptr. In any case, the copy constructor and copy assignment will need to be taken into consideration. The compiler-provided defaults will likely not suffice.
Fred Larson
Well, I'm not sure if I really need this. If I remember correctly, I read in Effective C++ that a default destructor calls all the destructors of the class' fields. Is it true or have I understood?
artknish
It works for your first case. In the second case destructor of the class will free memory that is acquired by pointer itself but it won't release memory which was allocated by new - you should this by yourself. Simply use your first case unless my_ints have to live longer then your FieldStorage.
Mykola Golubyev
+1  A: 

First way is the prefereable one to use, you don't need pointer on vector and have forgot to delete it.

bb
I would say "preferred" rather than "right".
Fred Larson
I don't see any reason to use "vector *" as a member of the class in the pointed case. So "right" reflects how you should do. It can be "wrong" and still do the job.
Mykola Golubyev
+2  A: 

In the first example, the object is allocated on the stack.

The the second example, the object is allocated in the heap, and a pointer to that memory is stored on the stack.

Welbog
If the usage was "FieldStorage obj = new FieldStoreage();" how would that affect your answer? Are all primitives allocated on the stack? what about the ones added into the vector in the ctor, are they on the stack?
Binary Worrier
@Binary Worrier: "FieldStorage obj = new FieldStorage();" is nonsense. The return type of "new FieldStorage()" is `FieldStorage *`. As for your other questions, I don't know. It's been a while since I've used C++.
Welbog
If you allocate a FieldStorage on the heap, the vector uses part of that heap allocation. If you allocate a FieldStorage on the stack, the vector uses part of that stack allocation. If you define a global FieldStorage... well, you get the picture.
bk1e
@bk1e: thanks for the info!
Welbog
It should be "FileStorage*". Aside from that, your assertion that "primitives" are allocated on the stack is Nonsense. They can be allocated on the heap like anything else. You're thinking of variables in methods, which has nothing to do with the question as asked, and can only confuse the issue.
Binary Worrier
LB
@Welbog: You mean I can't allocate a int on heap? then what does int* p = new int do?
Naveen
I'm also with bk1e, I couldn't agreemore. My problem is with Weblogs blanket assertion that primitives are created on the stack).
Binary Worrier
@Naveen: it allocates an int on the heap, just as you would imagine.
Binary Worrier
Editted answer to reflect reality.
Welbog
@Weblog: Removed my downvote
Binary Worrier
+3  A: 

As Mykola Golubyev pointed out, you need to delete the vector in the second case.

The first will possibly build faster code, as the optimiser knows the full size of FieldStorage including the vector, and could allocate enough memory in one allocation for both.

Your second implementation requires two separate allocations to construct the object.

Binary Worrier
+1  A: 

the difference is that the second allocates the vector dynamically. there are few differences:

  • you have to release memory occupied by the vector object (the vector object itself, not the object kept in the vector because it is handled correctly by the vector). you should use some smart pointer to keep the vector or make (for example in the destructor):

    delete my_ints;

  • the first one is probably more efficient because the object is allocated on the stack.

  • access to the vector's method have different syntax :)

oo_olo_oo
A: 

In the first case, the std::vector is being put directly into your class (and it is handling any memory allocation and deallocation it needs to grow and shrink the vector and free the memory when your object is destroyed; it is abstracting the memory management from you so that you don't have to deal with it). In the second case, you are explicitly allocating the storage for the std::vector in the heap somewhere, and forgetting to ever delete it, so your program will leak memory.

Brian Campbell
"and it is handling any memory allocation and deallocation it needs to grow and shrink the vector" . . . happens in both cases.
Binary Worrier
+3  A: 

I think you are really looking for the difference between the Stack and the Heap.

The first one is allocated on the stack while the second one is allocated on the heap.

Floetic
What is the proper name for "member on the stack"? It sounds weird. How can we call it "stack" if we don't know how the instance of the object will be allocated?
Mykola Golubyev
-1 Incorrect. In the first case, my_ints is allocated as part of the object. Whether it is on the stack or on the heap depends upon how the instance itself was allocated. In the second case, it's a separate heap allocation.
Fred Larson
Fred, I think you are right. That would make sense. Thanks.
Floetic
In the second case, is it always a heap allocation?
Floetic
Technically, I believe the standard uses the term "free store" for the place where the new operator gets its memory, not "heap". In practice, most compilers seem to use malloc(), and everyone knows what you mean. So it depends on how pedantic you want to get. 8v)
Fred Larson
+1  A: 

The first version of FieldStorage contains a vector. The size of the FieldStorage class includes enough bytes to hold a vector. When you construct a FieldStorage, the vector is constructed right before the body of FieldStorage's constructor is executed. When a FieldStorage is destructed, so is the vector.

This does not necessarily allocate the vector on the stack; if you heap-allocate a FieldStorage object, then the space for the vector comes from that heap allocation, not the stack. If you define a global FieldStorage object, then the space for the vector comes from neither the stack nor the heap, but rather from space designated for global objects (e.g. the .data or .bss section on some platforms).

Note that the vector performs heap allocations to hold the actual data, so it is likely to only contain a few pointers, or a pointer and couple of lengths, but it may contain whatever your compiler's STL implementation needs it to.

The second version of FieldStorage contains a pointer to a vector. The size of the FieldStorage class includes room for a pointer to a vector, not an actual vector. You are allocating storage for the vector using new in the body of FieldStorage's constructor, and you leaking that storage when FieldStorage is destructed, because you didn't define a destructor that deletes the vector.

bk1e
A: 

The size of the object is going to be different. In the second case the Vector<>* only takes up the size of a pointer (4bytes on 32bit machines). In the first case, your object will be larger.

jeffamaphone
+13  A: 

In terms of memory management, these two classes are virtually identical. Several other responders have suggested that there is a difference between the two in that one is allocating storage on the stack and other on the heap, but that's not necessarily true, and even in the cases where it is true, it's terribly misleading. In reality, all that's different is where the metadata for the vector is allocated; the actual underlying storage in the vector is allocated from the heap regardless.

It's a little bit tricky to see this because you're using std::vector, so the specific implementation details are hidden. But basically, std::vector is implemented like this:

template <class T>
class vector {
public:
    vector() : mCapacity(0), mSize(0), mData(0) { }
    ~vector() { if (mData) delete[] mData; }
    ...
protected:
    int mCapacity;
    int mSize;
    T *mData;
};

As you can see, the vector class itself only has a few members -- capacity, size and a pointer to a dynamically allocated block of memory that will store the actual contents of the vector.

In your example, the only difference is where the storage for those few fields comes from. In the first example, the storage is allocated from whatever storage you use for your containing class -- if it is heap allocated, so too will be those few bits of the vector. If your container is stack allocated, so too will be those few bits of the vector.

In the second example, those bits of the vector are always heap allocated.

In both examples, the actual meat of the vector -- the contents of it -- are allocated from the heap, and you cannot change that.

Everybody else has pointed out already that you have a memory leak in your second example, and that is also true. Make sure to delete the vector in the destructor of your container class.

Eric Melski
Actually, they are right - in the first case the vector object is allocated on the stack - the fact that it internally allocates memory on the heap has nothing to do with this fact.
Nemanja Trifunovic
Nemanja: how so? What if I declare my object like this: FieldStorage* fs = new FieldStorage(); then it is stored on the heap. Yes, in the specific sample code given, he declares it on the stack - but the question seems (to me) to be asking the difference between declaring a pointer or ...
Dan
... non-pointer member, rather than "whats the difference in this particular sample code". Of course, you are absolutely correct for the sample code and if thats what was meant, I apologise. :-)
Dan
@Nemanja: I believe I addressed that in my answer, and Dan clarified my point already. Anyway, the most important thing is where the bulk of the memory usage is coming from. That is the vector contents, not the metadata, and the contents are always heap allocated.
Eric Melski
+1 Excellent answer.
Fred Larson
I believe you meant well but the first sentence of your answer is confusing: "In terms of memory management, these two classes are virtually identical.". In the second example, the class contains one pointer, and in the first case a vector object with all the "metadata" as you say.
Nemanja Trifunovic
@Nemanja: Yes, the first class contains a pointer: 4 bytes on a 32-bit system. The second contains the vector metadata: 12 bytes on the same system. The difference is 8 bytes -- virtually identical, and surely not as interesting as the multiple KB or MB used for the vector contents.
Eric Melski
@Eric: Thanks for the answer!
artknish
+1 Excellently complete answer
Binary Worrier
A: 

One practical difference is that in your second example, you never release either the memory for the vector, or its contents (because you don't delete it, and therefore call its destructor).

But the first example will automatically destroy the vector (and free its contents) upon destruction of your FieldStorage object.

Larry Gritz