Lets say I have an object that I dynamically allocated.
If I push it into a STL vector, will a reference be inserted into the vector or a copy of this object?
It's a general question. For example:
class vec {
vector<obj> vec;
void addToVec(obj a) {
// insert a into vec
}
...
...
...
}
obj* a = new obj;
vec* v = new vec;
vec.addToVec(a);
If I delete v, will object a die as well?
will a reference be inserted into the vector or a copy of this object?
Copy (which means that your class should be copy-able otherwise compiler error).
Clarification: References cannot be assigned in std::vector<>. Also, here object has broader sense, it can be a normal variable or a pointer, but std::vector<> accepts only copy.
Update: Post C++11, most of the standard containers offer std::move() of the object using "rvalue based API methods"; where a copy may not be performed.
If you have an object of type T that you have dynamically allocated and you push a pointer to the object onto a std::vector<T*>, then a copy of the pointer is pushed. If you dereference the pointer and push the result onto a std::vector<T>, then a copy of the object is made. Collections always make copies. So collections of pointers make copies of the pointer and collections of class instances make copies of the instances themselves (using copy construction IIRC).
Have you checked the reference:
void push_back ( const T& x );
Add element at the end
Adds a new element at the end of the vector, after its current last element. The content of this new element is initialized to a copy of x.
This effectively increases the vector size by one, which causes a reallocation of the internal allocated storage if the vector size was equal to the vector capacity before the call. Reallocations invalidate all previously obtained iterators, references and pointers
Related
If I use this line
std:vector<MyObject>* vec = new std::vector<MyObject>(100);
If I create MyObject's in the stack and add them to the vector, they remain in the stack, right ?
MyObject obj1;
vec->push_back(obj1);
So if it go to the stack, than MyObject's added to the vector will be gone after method ends ? What will I have inside the vector than? Garbage?
Should I use this instead ?:
std:vector<MyObject*>* vec = new std::vector<MyObject*>(100);
And if so, what about objects and primitives inside each MyObject ?
Should they also be dynamically created ?
Thank You
The std:vector as any other Standard Library container copies elements into itself, so it owns them. Thus, if you have a dynamically allocated std::vector the elements that you .push_back() will be copied into the memory managed by the std::vector, thus they will be copied onto the heap.
As a side note, in some cases std::vector may move elements if it is safe to do so, but the effect is the same - in the end, all the elements are under std::vector's jurisdiction.
A std::vector<MyObject> looks something like this (in reality it's much more complex):
struct Vector {
MyObject* data;
int size;
}
As you can see, the data is not directly inside the vector object. The vector always allocates the memory for the data on the heap. Here's what happens when:
you call .push_back: The vector copies the object into its own data block (which is on the heap and owned by the vector)
you copy the vector: The copied vector allocates new memory and copies all data from the existing vector into it
As you can see, the vector owns his data. That means, if you push_back a object into it, it doesn't matter where it came from because it gets copied.
If you have a std::vector<MyObject>* you have a pointer to a vector. This vector also owns his data, but you only have a pointer to it. That means, you have to delete it exactly once, otherwise you'll get a memory leak or a crash. Passing around pointers to a vector is OK, but need one class or function that "owns" it. This class/function has to guarantee that the vector still exists when the pointer to it is used.
The third case is a std::vector<MyObject*>. As every vector, this one also owns his data. But this time, the data is only a pointer. So the vector only owns the pointer, but not the objects to which the pointers are pointing. If you do something like this:
std::vector<MyObject*> getObjects() {
MyObject obj1("foo");
MyObject obj2("bar");
std::vector<MyObject*> vec;
vec.push_back(&obj1);
vec.push_back(&obj2);
return vec;
}
The returned vector only contains garbage because you only saved the address to a object on the stack to it. These objects are destroyed when the function returns, but the pointers in the vector are still pointing to that memory block on the stack.
Additionally, keep in mind that this
std:vector<MyObject*>* vec = new std::vector<MyObject*>(100);
Doesn't store heap allocated objects to the vector. It just stores pointers of type MyObject. If you want to do something like that remember to create the objects first, before you use them. You can do that with something like the following:
for (int i = 0; i < vec->size(); i++) {
vec->at(i) = new MyObject();
}
From my understanding so far, if you have a vector of class objects, if you erase any member of the vector, typically the vector will reallocate some of it's objects in order to preserve memory contiguousness. Hence you need to implement the rule of three (destructor, copy constructor and copy assignment operator) for everything to be preserved when erasing vector members.
However: for a vector of pointers to class objects the outcome is less clear to me.
If I erase a member, then surely C++ is smart enough to just copy the pointers around - not maddeningly delete the pointer (and the class object it points to) then re-create it and the object it points to again?
If this is not the case, can someone explain this idiocy to me?
The vector will delete, construct, and copy whatever type it contains. In the case of a vector of pointers to a class/structure, it will delete, construct, and copy pointers, leaving the actual objects the pointers point to alone. It is up to you to allocate and deallocate these.
EDIT
An example:
If you have the following:
class A
{
A() {}
}
void foo(void)
{
A * pointerToA = new A;
}
At the end of the function foo's scope the only thing that is deallocated is the memory for the variable pointerToA itself, i.e. 4 bytes that hold an address (in 32 bit) - which in this case is stored on the stack. The only way that the memory allocated for a new instance of class A will be freed is if you manually call delete with the address to pointerToA.
Let's take the example of an array of class A
A ** arrayOfPointerToA = new A*[10];
for(unsigned i = 0; i < 10; ++i)
arrayOfPointerToA[i] = new A;
which is similar to what happens when you have std::vector<A*>. When you call
delete [] arrayOfPointerToA;
you're deallocating the memory for the array of pointers, not for each A.
In the above diagram, the memory deallocated by the above call to delete is highlighted in red. Note that each A is stored at a random location in memory in this instance since they were all allocated separately.
Now taking this to a vector:
A std::vector<A> effectively uses new A[size] to allocate memory. If you're storing a raw pointer, this would mean it would allocate an array of type A, which means that size number of objects of type A are created. When the vector frees its memory size number of objects of type A are destroyed. Now take that example and replace A with A* and you'll see that no objects of type A are destroyed.
This is a fundamental part of how C++ and pointers work, not just a property of containers. If containers did arbitrarily call delete on each member, this wouldn't make sense as when we have a container A we would call delete on an instance of an object instead of a pointer to that object which is not valid.
The vector will leave your pointer values alone. It of course will move the values in the internal array when you push, pop, or erase.
In this case the values are just pointers. But there is no logic in the vector to determine if something is a pointer to an object and delete/reallocate them when the values are copied.
In the case of a vector that includes a complex type and not a pointer it will of course try to copy the values when the internal array is reallocated or moved.
In C++ what happens if you create an object on the stack (within a function) and insert it into a heap-allocated container (which has been passed into the function/exists after the function finishes)?
The stack object has local scope, but the container it has been inserted within, is on the heap and can last after the function (where the insert was made) has returned. Is the stack object still retrievable from the container after the function returns?
void Test( std::vector<MyClass>& myvec )
{
MyClass m;
myvec.push_back(m);
}
In this particular case, m will be copy-constructed into a new instance of MyClass, which will be owned by the vector. So a different but equivalent instance of MyClass can be retrieved from the vector, yes.
Base assumption: when you use Vector, you really mean std::vector. The answer could change with a container that's designed enough differently.
As long as you do like you usually should, and store objects (not pointers) in the container, you're all right, because what's stored in the container is normally a copy of the object you pass.
Under the right circumstances, the object in the container can be move constructed from what you pass, but the effect is basically the same -- you end up with an object whose lifetime continues until it's removed from the container (or the container is destroyed, etc.)
Is the stack object still retrievable from the container after the function returns?
Yes, your myvec.push_back(m); makes a copy of m and a new copy is manged by vector.
However, after your function returns myvec doesn't have m inside because you pass myvec into Test function by value, Test function makes a temporary copy of myvec and copy m into it, after function returns the temporary copy of myvec is released. So you meant to pass myvec to Test function by reference as below:
public void Test(Vector<MyClass>& myvec){
MyClass m;
myvec.push_back(m);
}
As noted by other answers, m is copied into vector. That said, your function receives vector by value too (UPD: it was true for the original code, which was edited since), and it's obviously not what you wanted.
The code in the question will create a copy of MyClass in the std::vector. The original m will be destructed when the Test method exits.
If we change the vector to store pointers to MyClass we have two possible options.
void Test( std::vector<MyClass*>& myvec )
{
// Allocates a new MyClass on the heap.
MyClass* pM = new MyClass();
myvec.push_back(pM);
// This variable will be allocated on the stack and cleaned up on method exit
MyClass dontDoThis;
myvec.push_back(&dontDoThis);
}
At the end of this method myvec has two elements, myvec[0] and myvec[1].
When a container of pointers is stored then the object must be allocated so that it is valid for the length of time the pointer is in the container. In the example above the pM pointer will be valid after the Test method exits. This means that myvec[0] will be a valid pointer after the method exits.
Initially, a valid pointer to dontDoThis variable will be added to the vector, but when the method exits the destructor of dontDoThis will be called and the memory will probably be used to store other data. The pointer in myvec looks ok, but any attempt to actually use it will cause undefined behaviour. On method exit the pointer in myvec[1] might look valid, but actually it points to junk.
Note that at a later time, when myvec[0] is changed or deleted, it is important to call:
delete myvec[0]
to ensure that the object is cleaned up properly. Otherwise a memory leak will occur.
After explaining what will happen with naked pointers, I strongly recommend you use smart pointers such as std::unique_ptr and std::shared_ptr
Is the stack object still retrievable from the container after the function returns?
Only if MyClass has a "gut" copy constructor. (Deep copy or sharing ownedship of other resuorses, etc)
I mean, it could be retrived but it could be in a broked state
I basically have a
vector<Object> vec_;
as a class member in a cpp class. At a certain class function this vector will be filled with "Objects" just like this:
vec_.push_back(Object());
At a later time I iterate through the vector elements and keep a pointer to the best element. Then the vector is cleared as shown in the following:
Object* o_ptr = &(vec_[0]);
for (unsigned int i = 1; i < vec_.size(); i++) {
if (o_ptr->getCost() > vec_[i].getCost()) {
o_ptr = &(vec_[i]);
}
vec_.clear();
Now my question is: What happens to the objects removed from the vector? Is their lifetime over as soon as the they are removed from the vector? And does the pointer also point to empty space then?
And if not when does the lifetime of these objects end?
Regards scr
When vector.clear() is called (or when the vector is destructed) all objects contained with the vector will be destructed (as in this case they are objects and not raw pointers), leaving o_ptr as a dangling pointer.
Note that caching the address (or iterator) of an element in vector is dangerous, even without a call to clear(). For example, push_back() could result in internal reallocation of the vector, invalidating the cached address (or iterator).
What happens to the objects removed from the vector?
They are destructed.
Is their lifetime over as soon as the they are removed from the vector?
Yes.
Does the pointer also point to empty space then?
Yes it does. If you want to save the object, make a copy of it before clearing the vector.
It's also important to note that certain vector operations might leave pointers pointing to nothing even if the vector is not cleared. Specifically resizes, which typically involve a reallocation. It's generally best to store references to vector elements by index, since you will always be able to get the element via the index (whereas a pointer may be invalidated after certain operations).
The subscript operator, applied to vectors, returns a reference and does not make a copy.
The objects are owned by the vector and .clear() indeed removes them.
In addition, pointing to the objects stored in a std::vector is a bit dangerous. If you push new elements to the vector, at some point the vector might need to allocate more memory - which is likely to copy all the previous elements to a different address using their copy constructor (hence invalidating your pointers).
So: Use integer indices with std::vector instead of pointers, unless you know that you won't be pushing beyond the reserved capacity (which you can assure using .reserve()).
(Also while we're at it, make sure not to confuse the vector's internal buffer size with .size(), which is simply the number of actual elements stored).
The best way to track the lifetime of an object is to add a printf to both the constructor and destructor.
class MyObject
{
public:
MyObject()
{
printf("MyObject constructed, this=%p\n", this);
}
~MyObject()
{
printf("MyObject destructed, this=%p\n", this);
}
};
I have a std::vector of Element*. When will the destructor be called.
How is it different if it is a vector of Element
std::vector<Element*> vect;
..
struct Element
{
Record *elm;
Element(Record *rec)
{
elm = new Record();
//...copy from rec
}
~Element()
{
delete elm;
}
};
I am using the vector as follows:
Element *copyElm = new Element(record);
vect.push_back(copyElm);
In the above code, how can I ensure there's no leak.
You could use a reference-counting pointer-wrapper class in your array, and the items will automatically get deleted whenever there are no more references to them. One such class is boost::shared_ptr. You will also find it in some compiler's shipping C++ libraries because it is being added to a future version of C++.
std::vector<boost::shared_ptr<Element> > vect;
These classes wrap operator ->, etc, so you can use them in most of the same ways that you'd used a normal pointer.
http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/shared_ptr.htm
Whenever you free the class Element instance yourself. The vector will free the vector elements (the pointers), but not the class Element objects pointed to. After all, the vector has no way to know if you have other pointers to the same object.
vector will call release the memory of the object it is holding (i.e. pointers) but will not release the memory of the object it is pointing to. You need to release the memory of the Element object yourself. If it was a vector<Element> then whenever you do a push_back a copy of the element is inserted into the vector. vector guarntess that it will release the memory allocated to this copied object. But be aware with the current definition of Element you will get a seg fault as you have not defined the copy ctor and assignment operator.
EDIT
If you for some reason don't want to use smart pointers, then only option is to write a release function which goes through the entire vector and calls the delete on the stored pointer.
In a vector of Element, the destructor is called a lot. Whenever a node is assigned, the vector is sized down, the vector has to move in memory, or the vector goes out of scope/is destroyed, destructors are called on the elements before they are changed/discarded. Also, the copy constructor is called for assignment, and the default constructor is called to initialize each entry. Sorting such a vector will involve a lot of both copying and destroying.
In a vector of Element* it is never called, unless you call delete yourself.
Take a look at Boost shared_ptr for a saner solution, or unique_ptr if you have a compiler with relatively new features.
Destroying a pointer is always a no-op, and there are several good reasons why.