The folowing constructor
std::vector<Object> objects(n);
creates n objects calling the default constructor, i.e. something like that:
std::vector <Object> objects;
for (unsigned int i = 0; i < n; i++) objects.push_back(o);
Is this procedure also valid for dynamically allocated objects? Does the construction
std::vector<Object *> objects(n);
represent this functionality?
std::vector <Object*> objects;
for (unsigned int i = 0; i < n; i++) objects.push_back(new Object());
If not, is there a way how to arrange it?
std::vector<Object> objects(n);
The behavior of this depends on which version of the C++ Standard your Standard Library implementation implements:
In C++03, this creates one default constructed Object and then copy constructs that object n times.
In C++0x, this default constructs n Objects.
The difference shouldn't usually matter, but it's good to know.
std::vector<Object *> objects(n);
This creates a vector with n null Object*s in it. Since Object* is not a class type and does not have a constructor, the newly inserted objects are value initialized, which for pointers means they are set to NULL.
If you want to dynamically create new objects and then store pointers to them in the container, you need to call new yourself. Note that you should not be storing raw pointers in a standard library container if the container owns the pointed-to objects. Doing so is not exception safe.
You should be using a smart pointer like shared_ptr or unique_ptr instead (note: the auto_ptr smart pointer cannot be stored in containers due to its unusual copy semantics, thus shared_ptr or unique_ptr should be used).
In any case, to insert pointers to n distinct, dynamically allocated objects into the container, you need to call new n times to create those n objects. There's nothing wrong with your for loop solution.
The folowing constructor
std::vector<Object> objects(n);
creates n objects calling the default constructor
Yes, but the default constructor is used only to construct the second optional parameter to the constructor of vector, the n objects in the vector are constructed by copying this parameter. [C++03 answer]
If you did something like:
std::vector<Object*> objects(n, new Object());
you would dynamically allocate one object and have n pointers to that object in your vector which is probably not what you want.
It is almost always a bad idea to use a container of pointers if that container is supposed to own the dynamically allocated objects. You should consider something like boost::ptr_vector, or if that is not possible a container of smart pointers (not std::auto_ptr, though).
No, the vector won't be automatically created with pointers to Object instances. You will have to perform the for loop you have written in order to populate it correctly.
You will also need to delete each of these objects when you have finished with them too.
Your final code example has the right general idea, but tread carefully: vector will not manage the allocations for you if you do that! objects.clear() will leak memory, for instance.
You probably want to use std::vector<some_smart_ptr<Object> > instead, but choosing the right smart pointer class requires care and attention to (for instance) what happens when you copy elements from one vector to another. boost::shared_ptr is a safe choice, but may have unnecessary overhead for your use case. boost::ptr_vector may be better.
Related
I have this:
std::vector<Pair *> *artistAttributes;
where Pair is a class, how can I add an element into this pointer?
I know how to access this if it was just a std::vector like so,
std::vector<Pair *> artistAttributes;
But I am unfamiliar with how to add elements into this since I am very new to pointers.
I am very knew to pointers.
There is a semantic difference between pointers that just point to objects on the automatic-storage ("stack") and pointers to objects on the free-store ("heap") in that pointers to objects on the heap must at some point be used to deallocate (delete/delete[]) the memory earlier allocated with new (or new[]).
This is not just easily forgotten but cannot be done when an exception is thrown between allocation and deallocation. To make that simpler, smart pointers were invented which follow the RAII/RDID-idiom ("Resource Acquisition Is Initialisation/Resource Destruction is Deletion"): Raw pointers are encapsulated in Objects that manage the lifetime of the resource they handle.
This makes it possible in many circumstances to avoid following the Rule of 3/5 (which is more a Rule of the Big Four (and a half) in modern C++) but use the Rule of Zero instead.
Also, there is no real point in having a pointer to a std::vector<> since vectors are cheap to copy (compared to the inconvenience of having to manage dynamically allocated memory).
So instead of
std::vector<Pair *> *artistAttributes;
better use
std::vector<std::shared_ptr<Pair>> artistAttributes;
Normally you access a member of an object with the . operator. If you wanna access the member of a pointer to an object you use the -> operator instead.
So you can modify the vector with artistAttributes->push_back() (to add a new element) or artistAttributes->at() (to modify an existing element). Equivalently you can also do (*artistAttributes).push_back() and (*artistAttributes).at().
See this:
std::vector<Pair*> *artistAttributes;
artistAttributes = new std::vector<Pair*>;
artistAttributes->push_back(new Pair())
...
for(int i=0; i<artistAttributes->size(); i++)
delete (*artistAttributes)[i] // Don't forget
delete artistAttributes; // Don't forget
In comparison to:
std::vector<Pair*> artistAttributes;
//artistAttributes = new std::vector<Pair*>; // no needed
artistAttributes.push_back(new Pair()) // use . instead of ->
...
for(int i=0; i<artistAttributes.size(); i++)
delete artistAttributes[i] // Don't forget
and in comparison to:
std::vector<Pair> artistAttributes;
//artistAttributes = new std::vector<Pair*>; // no needed
artistAttributes.push_back(Pair())
Hello I have this question:
I would like to have a vector as class member. This is perhaps my question
easier for you and I apologize for that.
how should I declare the vector? And is this correct? std::vector<int> *myVector; or std::vector<int> myVector ?
how should I handle this vector in dealloc?
How can I initialize the array into a if?
Is this correct?
if(myCondition)
{
if(!myVector) //is this correct?
myVector = new std::vector<int>(); //is this correct? on this i have a error
}
You most certainly want to use std::vector<int> myVector. No need to initialize it, as it gets automatically initialized in the constructor of your class and deallocated when your class is destroyed.
Just use automatic allocation: declare it as a member like this:
class YourClass
{
std::vector<int> myVector;
// ...
};
The array gets constructed automatically before any of your constructor is run and is destroyed automatically when your object is deallocated, you don't need to care about it (also, the default copy constructor and assignment operator will handle copying gracefully automatically).
If, instead, you want to create the array only after a particular condition, you have to resort to a (smart) pointer and dynamic allocation, but IMHO it's quite cumbersome (especially because you then have to get right the "big three" - copy constructor, assignment operator, destructor); you could instead simply allocate the vector with automatic allocation and use a separate flag to mark your array as not initialized, or just check if its size is 0.
That depends entirely on context - what the vector means and why you need it. Should it be shared among multiple objects? If you don't know, don't keep a pointer, go with your second option.
std::vector<int> myVector;
If you have strong reasons to have a pointer, then please use a smart pointer, the one that provides most appropriate ownership for your situation - shared_ptr, scoped_ptr, unique_ptr or whatever_ptr
Most of the time, when we use standard library, We do not need to care about the memory allocation/deallocation. The template will handle it automatically. eg. The memory of a std::vector will be increase or decrease according to the elements stored in this vector. This would be an example.
Therefore, almost you can use it this way in your case.
std::vector<int> myVector //your second declaration
if(myCondition)
{
myVector.push(some_int); // use it directly
}
The memory the vector used will be deallocated when the Class object you created is destroyed.
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.
Consider the following public method that adds an integer variable to a vector of ints(private member) in a class in C++.
KoolMethod()
{
int x;
x = 10;
KoolList.Add(x);
}
Vector<int>KoolList;
But is this a valid addition to a vector ??? Upon calling the method, it creates a local variable. The scope of this local variable ends the moment the execution control leaves the method. And since this local variable is allocated on a stack(on the method call), any member of KoolList points to an invalid memory location in deallocated stack which may or may not contain the expected value of x. Is this an accurate description of above mechanism ??
Is there a need for creating an int in heap storage using "new" operator everytime a value needs to be added to the vector like described below ????:
KoolMethod()
{
int *x = new int();
*x = 10;
KoolList.Add(x);
}
Vector<int*>KoolList;
But is this a valid addition to a vector?
Yes, a (standard library) vector stores copies.
Is there a need for creating an int in heap storage using "new" operator
If you don't want the objects to be copied or to work with polymorphic objects (see object slicing) you'd use pointers. In that case you should preferably avoid dealing with deallocation manually and use wrappers (smart pointers or pointer containers) though to get exception safety back.
A Vector<int> (at least if it is std::vector) stores elements by value, so calls to add() creates a copy of the parameter object and stores that copy into the array. Therefore it doesn't matter what happens with the original object, the copy within the vector is alive as long as the vector itself (unless removed or overwritten explicitly, of course).
A Vector<X*> may be more appropriate if you
want to work with polymorphic X objects,
don't want to copy objects of X e.g. because it's expensive or disallowed,
want to share the same objects between different parties.
Of course, none of these applies to int, only to real objects. Still, it is better to store smart pointers in the vector instead of raw pointers, e.g. vector<auto_ptr<X> > or vector<shared_ptr<X> >. These automatically manage the disposal of objects for you.
If you create a vector of ints, it will not be a vector of pointers. The integers are stored by value, no pointers involved, and therefore you won't run into any problems with invalid memory addresses.
Here's an example of code that would cause such a problem:
std::vector<int *> my_list;
void a_method() {
int value = 2; // allocated on the stack
my_list.push_back(&value); // pushes a pointer to the stack... not good
}
Think about this: adding to the standard vector creates copy of added object.
In the first code snippet, you use vector of ints, so you'll add the copy of local int and everything is fine.
In the second code snippet you use vector of pointers to int, so you'll add the copy of a pointer (not the copy of the object this pointer is pointing to). Since the object pointed by the pointer will be still valid after leaving the method (it's initialized using new operator and it's not deleted anywhere) everything will be fine too.
How does container object like vector in stl get destroyed even though they are created in heap?
EDIT
If the container holds pointers then how to destroy those pointer objects
An STL container of pointer will NOT clean up the data pointed at. It will only clean up the space holding the pointer. If you want the vector to clean up pointer data you need to use some kind of smart pointer implementation:
{
std::vector<SomeClass*> v1;
v1.push_back(new SomeClass());
std::vector<boost::shared_ptr<SomeClass> > v2;
boost::shared_ptr<SomeClass> obj(new SomeClass);
v2.push_back(obj);
}
When that scope ends both vectors will free their internal arrays. v1 will leak the SomeClass that was created since only the pointer to it is in the array. v2 will not leak any data.
If you have a vector<T*>, your code needs to delete those pointers before delete'ing the vector: otherwise, that memory is leaked.
Know that C++ doesn't do garbage collection, here is an example of why (appologies for syntax errors, it has been a while since I've written C++):
typedef vector<T*> vt;
⋮
vt *vt1 = new vt, *vt2 = new vt;
T* t = new T;
vt1.push_back(t);
vt2.push_back(t);
⋮
delete vt1;
The last line (delete vt1;) clearly should not delete the pointer it contains; after all, it's also in vt2. So it doesn't. And neither will the delete of vt2.
(If you want a vector type that deletes pointers on destroy, such a type can of course be written. Probably has been. But beware of delete'ing pointers that someone else is still holding a copy of.)
When a vector goes out of scope, the compiler issues a call to its destructor which in turn frees the allocated memory on the heap.
This is somewhat of a misnomer. A vector, as with most STL containers, consists of 2 logical parts.
the vector instance
the actual underlying array implementation
While configurable, #2 almost always lives on the heap. #1 however can live on either the stack or heap, it just depends on how it's allocated. For instance
void foo() {
vector<int> v;
v.push_back(42);
}
In this case part #1 lives on the stack.
Now how does #2 get destroyed? When a the first part of a vector is destroyed it will destroy the second part as well. This is done by deleting the underlying array inside the destructor of the vector class.
If you store pointers in STL container classes you need to manually delete them before the object gets destroyed. This can be done by looping through the whole container and deleting each item, or by using some kind of smart pointer class. However do not use auto_ptr as that just does not work with containers at all.
A good side effect of this is that you can keep multiple containers of pointers in your program but only have those objects owned by one of those containers, and you only need to clean up that one container.
The easiest way to delete the pointers would be to do:
for (ContainerType::iterator it(container.begin()); it != container.end(); ++it)
{
delete (*it);
}
Use either smart pointers inside of the vector, or use boost's ptr_vector. It will automatically free up the allocated objects inside of it. There are also maps, sets, etc.
http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/ptr_vector.html
and the main site:
http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/ptr_container.html
As with any other object in the heap, it must be destroyed manually (with delete).
To answer your first question:
There's nothing special about STL classes (I hope). They function exactly like other template classes. Thus, they are not automatically destroyed if allocated on the heap, because C++ has no garbage collection on them (unless you tell it to with some fancy autoptr business or something). If you allocate it on the stack (without new) it will most likely be managed by C++ automatically.
For your second question, here's a very simple ArrayOfTen class to demonstrate the basics of typical memory management in C++:
/* Holds ten Objects. */
class ArrayOfTen {
public:
ArrayOfTen() {
m_data = new Object[10];
}
~ArrayOfTen() {
delete[] m_data;
}
Object &operator[](int index) {
/* TODO Range checking */
return m_data[index];
}
private:
Object *m_data;
ArrayOfTen &operator=(const ArrayOfTen &) { }
};
ArrayOfTen myArray;
myArray[0] = Object("hello world"); // bleh
Basically, the ArrayOfTen class keeps an internal array of ten Object elements on the heap. When new[] is called in the constructor, space for ten Objects is allocated on the heap, and ten Objects are constructed. Simiarly, when delete[] is called in the destructor, the ten Objects are deconstructed and then the memory previously allocated is freed.
For most (all?) STL types, resizing is done behind the scenes to make sure there's enough memory set asside to fit your elements. The above class only supports arrays of ten Objects. It's basically a very limiting typedef of Object[10].
To delete the elements pointed at, I wrote a simple functor:
template<typename T>
struct Delete {
void operator()( T* p ) const { delete p; }
};
std::vector< MyType > v;
// ....
std::for_each( v.begin(), v.end(), Delete<MyType>() );
But you should fallback on shared pointers when the vector's contents are to be ... ehm... shared. Yes.
A functor that deletes pointers from STL sequence containers
The standard STL containers place a copy of the original object into the container, using the copy constructor. When the container is destroyed the destructor of each object in the container is also called to safely destroy the object.
Pointers are handled the same way.
The thing is pointers are POD data. The copy constructor for a pointer is just to copy the address and POD data has no destructor. If you want the container to manage a pointer you need to:
Use a container of smart pointers. (eg shared pointer).
Use a boost ptr container.
I prefer the pointer container:
The pointer containers are the same as the STL containers except you put pointers into them, but the container then takes ownership of the object the pointer points at and will thus deallocate the object (usually by calling delete) when the container is destroyed.
When you access members of a ptr container they are returned via reference so they behave just like a standard container for use in the standard algorithms.
int main()
{
boost::ptr_vector<int> data;
data.push_back(new int(5));
data.push_back(new int(6));
std::cout << data[0] << "\n"; // Prints 5.
std::cout << data[1] << "\n"; // Prints 6.
} // data deallocated.
// This will also de-allocate all pointers that it contains.
// by calling delete on the pointers. Therefore this will not leak.
One should also point out that smart pointers in a container is a valid alternative, unfortunately std::auto_ptr<> is not a valid choice of smart pointer for this situation.
This is because the STL containers assume that the objects they contain are copyable, unfortunately std::auto_ptr<> is not copyable in the traditional sense as it destroys the original value on copy and thus the source of the copy can not be const.
STL containers are like any other objects, if you instantiate one it is created on the stack:
std::vector<int> vec(10);
Just like any other stack variable, it only lives in the scope of the function it is defined in, and doesn't need to be manually deleted. The destructor of STL containers will call the destructor of all elements in the container.
Keeping pointers in a container is a dicey issue. Since pointers don't have destructors, I would say you would never want to put raw pointers into an STL container. Doing this in an exception safe way will be very difficult, you'd have to litter your code with try{}finally{} blocks to ensure that the contained pointers are always deallocated.
So what should you put into containers instead of raw pointers? +1 jmucchiello for bringing up boost::shared_ptr. boost::shared_ptr is safe to use in STL containers (unlike std::auto_ptr). It uses a simple reference counting mechanism, and is safe to use for data structures that don't contain cycles.
What would you need for data structures that contain cycles? In that case you probably want to graduate to garbage collection, which essentially means using a different language like Java. But that's another discussion. ;)