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);
}
};
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.
I am totally confused with regards to deleting things in C++. If I declare an array of objects and if I use the clear() member function. Can I be sure that the memory was released?
For example :
tempObject obj1;
tempObject obj2;
vector<tempObject> tempVector;
tempVector.pushback(obj1);
tempVector.pushback(obj2);
Can I safely call clear to free up all the memory? Or do I need to iterate through to delete one by one?
tempVector.clear();
If this scenario is changed to a pointer of objects, will the answer be the same as above?
vector<tempObject> *tempVector;
//push objects....
tempVector->clear();
You can call clear, and that will destroy all the objects, but that will not free the memory. Looping through the individual elements will not help either (what action would you even propose to take on the objects?) What you can do is this:
vector<tempObject>().swap(tempVector);
That will create an empty vector with no memory allocated and swap it with tempVector, effectively deallocating the memory.
C++11 also has the function shrink_to_fit, which you could call after the call to clear(), and it would theoretically shrink the capacity to fit the size (which is now 0). This is however, a non-binding request, and your implementation is free to ignore it.
There are two separate things here:
object lifetime
storage duration
For example:
{
vector<MyObject> v;
// do some stuff, push some objects onto v
v.clear(); // 1
// maybe do some more stuff
} // 2
At 1, you clear v: this destroys all the objects it was storing. Each gets its destructor called, if your wrote one, and anything owned by that MyObject is now released.
However, vector v has the right to keep the raw storage around in case you want it later.
If you decide to push some more things into it between 1 and 2, this saves time as it can reuse the old memory.
At 2, the vector v goes out of scope: any objects you pushed into it since 1 will be destroyed (as if you'd explicitly called clear again), but now the underlying storage is also released (v won't be around to reuse it any more).
If I change the example so v becomes a pointer to a dynamically-allocated vector, you need to explicitly delete it, as the pointer going out of scope at 2 doesn't do that for you. It's better to use something like std::unique_ptr in that case, but if you don't and v is leaked, the storage it allocated will be leaked as well. As above, you need to make sure v is deleted, and calling clear isn't sufficient.
vector::clear() does not free memory allocated by the vector to store objects; it calls destructors for the objects it holds.
For example, if the vector uses an array as a backing store and currently contains 10 elements, then calling clear() will call the destructor of each object in the array, but the backing array will not be deallocated, so there is still sizeof(T) * 10 bytes allocated to the vector (at least). size() will be 0, but size() returns the number of elements in the vector, not necessarily the size of the backing store.
As for your second question, anything you allocate with new you must deallocate with delete. You typically do not maintain a pointer to a vector for this reason. There is rarely (if ever) a good reason to do this and you prevent the vector from being cleaned up when it leaves scope. However, calling clear() will still act the same way regardless of how it was allocated.
if I use the clear() member function. Can I be sure that the memory was released?
No, the clear() member function destroys every object contained in the vector, but it leaves the capacity of the vector unchanged. It affects the vector's size, but not the capacity.
If you want to change the capacity of a vector, you can use the clear-and-minimize idiom, i.e., create a (temporary) empty vector and then swap both vectors.
You can easily see how each approach affects capacity. Consider the following function template that calls the clear() member function on the passed vector:
template<typename T>
auto clear(std::vector<T>& vec) {
vec.clear();
return vec.capacity();
}
Now, consider the function template empty_swap() that swaps the passed vector with an empty one:
template<typename T>
auto empty_swap(std::vector<T>& vec) {
std::vector<T>().swap(vec);
return vec.capacity();
}
Both function templates return the capacity of the vector at the moment of returning, then:
std::vector<double> v(1000), u(1000);
std::cout << clear(v) << '\n';
std::cout << empty_swap(u) << '\n';
outputs:
1000
0
Move semantics allows for a straightforward way to release memory, by simply applying the assignment (=) operator from an empty rvalue:
std::vector<int> vec(100, 0);
std::cout << vec.capacity(); // 100
vec = vector<int>(); // Same as "vector<int>().swap(vec)";
std::cout << vec.capacity(); // 0
It is as much efficient as the "swap()"-based method described in other answers (indeed, both are conceptually doing the same thing). When it comes to readability, however, the assignment version makes a better job.
You can free memory used by vector by this way:
//Removes all elements in vector
v.clear()
//Frees the memory which is not used by the vector
v.shrink_to_fit();
If you need to use the vector over and over again and your current code declares it repeatedly within your loop or on every function call, it is likely that you will run out of memory. I suggest that you declare it outside, pass them as pointers in your functions and use:
my_arr.resize()
This way, you keep using the same memory sequence for your vectors instead of requesting for new sequences every time.
Hope this helped.
Note: resizing it to different sizes may add random values. Pass an integer such as 0 to initialise them, if required.
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
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.