How to add pointers into a pointer to a vector - c++

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())

Related

Does delete delete every element in a vector and free the memory?

vector<int>* v = new vector<int>;
for (int i = 0; i < 100; i++) {
(*v).push_back(i);
}
delete v;
Do I delete every element of the vector and free the memory? If not how do I free the memory?
An allocating new expression allocates memory, constructs a dynamic object into that memory, and returns a pointer to that object. When you pass such pointer to delete, the pointed object is destroyed and the memory is deallocated.
When an instance of a class, such as a vector is destroyed, its destructor is called. The destructor of vector destroys all elements of the vector.
Sidenote 1: It's rarely useful to use allocating new and delete. When you need dynamic storage, prefer to use RAII constructs such as containers and smart pointers instead.
Sidenote 2: You should avoid unnecessary use of dynamic memory in general. It's quite rare to need singular dynamic vector such as in your example. I recommend following instead:
std::vector<int> v(100);
std::ranges::iota(v, 0);
Sidenote 3: Avoid using (*v).push_back. It's hard to read. Prefer using the indirecting member access operator aka the arrow operator instead: v->push_back

Memory deallocation inside a member function

I was thinking about a this situation not for a real implementation but to understand better how pointers works.
class foo(){
foo();
~foo();
void doComplexThings(const std::vector<int*>& v){
int* copy;
for(int i = 0; i < v.size(); i++){
copy = v[i];
// do some stuffs
}
}
}
main(){
std::vector<int*> myVector; // suppose we have 100 elements
doComplexThings(myVector);
for(int i = 0; i < myVector.size(); i++){
delete myVector[i];
}
myVector.clear();
}
Ok, I know that have no sense to copy v[i] inside an other pointer, but I was thinking: copy do a memory leak?
After the execution of doComplexThings(), copy will continue to exist and will occupy space in the heap?
After deleting all elements it will continue to exist and point to a deallocated memory?
So logically if I do this things with complex objects I'll keep occupy the memory with unreference object? Or copy is saved in the stack because I don't use new? And at the end of doComplexThings it will be deleted?
I'm a bit confused, thanks!
There is some confusion on the topic of pointers in the C++ community. While it is true that smart pointers have been added to the library to alleviate problems with dynamic memory allocation, raw pointers are not obsolete. In fact, whenever you want to inspect another object without owning it, you should use a reference or raw pointer, depending on which suits your needs. If the concept of ownership is unclear to you, think of an object as being owned by another object if the latter is responsible for cleaning up afterwards (deleting the former).
For example most uses of new and delete should be replaces with the following (omitting std for brevity):
{
auto ptr_to_T = make_unique<T>(//constructor params);
do_stuff_with_smart_ptr(ptr_to_T);
do_stuff_with_T(*ptr_to_T);
do_stuff_with_raw_ptr(ptr_to_T.get());
} // automatic release of memory allocated with make_unique()
Notice how a function that takes a T* doesn't need a smart pointer if it doesn't keep a copy of the T* it is given, because it doesn't affect the lifetime of the object. The object is guaranteed to be alive past the return point of do_stuff_with_T() and its function signature signals that it doesn't own the object by taking a raw pointer.
On the other hand, if you need to pass the pointer to an object that is allowed to keep the pointer and reference it later, it is unclear when the object will need to be destroyed and most importantly by whom. This is solved via a shared pointer.
ClassThatNeedsSharedOwnership shared_owner;
{
auto ptr_to_T = make_shared<T>(//constructor params);
shared_owner.set_T(ptr_to_T);
// do a lot of stuff
}
// At this point ptr_to_T is destroyed, but shared_owner might keep the object alive
So how does the above factor in to your code. First of all, if the vector is supposed to own (keep alive) the ints it points to, it needs to hold unique_ptr<int> or shared_ptr<int>. If it is just pointing to ints held by something else, and they are guaranteed to be alive until after the vector is destroyed, you are fine with int*. In this case, it should be evident that a delete is never necessary, because by definition your vector and the function working on the vector are not responsible for cleaning-up!
Finally, you can make your code more readable by changing the loop to this (C++11 which you've tagged in the post):
for (auto copy : v){
// equivalent to your i-indexed loop with copy = v[i];
// as long as you don't need the value of i
do_stuff_to_int_ptr(copy);
// no delete, we don't own the pointee
}
Again this is only true if some other object holds the ints and releases them, or they are on the stack but guaranteed to be alive for the whole lifetime of vector<int*> that points to them.
No additional memory is allocated on the heap when you do this:
copy = v[i];
variable copy points to the same address as v[i], but no additional array is allocated, so there would be no memory leak.
A better way of dealing with the situation is to avoid raw pointers in favor of C++ smart pointers or containers:
std::vector<std::vector<int>> myVector;
Now you can remove the deletion loop, which is an incorrect way of doing it for arrays allocated with new int[length] - it should use delete[] instead:
delete[] myVector[i];
Basically you're illustrating the problem with C pointers which lead to the introduction of C++ unique and shared pointers. If you pass a vector of allocated pointers to an opaque member function, you've no way of knowing whether that function hangs onto them or not, so you don't know whether to delete the pointer. In fact in your example you don't seem to, "copy" goes out of scope.
The real answer is that you should only seldom use allocated pointers in C++ at all. The stl vector will serve as a safer, easier to use version of malloc / new. Then you should pass them about as const & to prevent functions from changing them. If you do need an allocated pointer, make one unique_ptr() and then you know that the unique_ptr() is the "owner" of the memory.

STL Containers & Memory Management - list of objects vs. list of pointers to objects

I have had a good look at some other questions on this topic and none of them (to my knowledge) address how to correctly erase items from a stl list of objects which contain dynamicically assigned memory vs. a stl list of objects that don't contain dynamically assigned memory.
I want to use a list of objects. Take this object for example (which contains no dynamically assigned memory):
class MyPoint {
public:
MyPoint(int _x,int _y)
{
x = _x;
y = _y;
}
private:
int x;
int y;
};
So I might create a list of objects (not pointers to them), add things to it and then erase an element:
list<MyPoint> myList;
myList.push_back(MyPoint(3,4));
myList.push_back(MyPoint(1,2));
myList.push_back(MyPoint(8,8));
myList.push_back(MyPoint(-1,2));
list<MyPoint>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
My list now contains:
(3, 4)
(1, 2)
(-1, 2)
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
Ok, now consider an alternative version of the class that allowed a point in N-dimensional space. I.e., I could dynamically assign an array of length N to hold the N points inside the class (I have spared you the implementation as that is not in question here). The destructor of the class would then delete the dynamically assigned array using 'delete'.
class MyDynamicPoint {
public:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete points;
points = NULL;
}
private:
int *points;
};
I might now create a list of pointers to the objects, instead of the objects themselves:
list<MyDynamicPoint*> myList;
myList.push_back(new MyDynamicPoint(8));
myList.push_back(new MyDynamicPoint(10));
myList.push_back(new MyDynamicPoint(2));
myList.push_back(new MyDynamicPoint(50));
list<MyDynamicPoint*>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
QUESTION 2a - Is the above correct? I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Many thanks in advance for any help,
Best,
Adam
When you have a class with data members that have automatic storage duration (i.e. their lifetime is tied to the instance of this class) like this:
class MyPoint {
private:
int x;
int y;
};
and you will use list<MyPoint> myList;, then this instance of std::list is also an object with automatic storage duration, that will be cleaned up automatically and by the time the container is destructed, so are the elements it holds. Everything is taken care of.
But the latter version is not very lucky choice... not only that you have a container holding pointers, you even decided to create a data member of class Point that will be allocated dynamically. At first note that everything that has been allocated by calling new should be freed by calling delete and everything allocating by calling new[] should be freed by calling delete[].
In this situation, you are allocating the memory when the object is constructed and cleaning it up when the object is destructed:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete[] points;
points = NULL;
}
private:
int *points;
You would achieve the same by using some std::vector or std::array instead of the C-style array and you wouldn't have to take care of the memory management on your own:
MyDynamicPoint(int N) : points(std::vector<int>(N, 0)) { }
private:
std::vector<int> points;
the std::vector object will take care of memory management for you.
And last thing: when you dynamically allocate an element and store it into the container:
myList.push_back(new MyDynamicPoint(8));
you need to free this memory on your own, erasing the pointer from the list is not enough:
list<MyDynamicPoint*>::iterator it;
...
delete *it;
myList.erase(it);
So whatever you want to achieve, always prefer objects with automatic storage duration if the situation allows it. There's nothing worse than being forced to taking care of memory management manually and dealing with unpleasant problems such as memory leaks later.
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
You don't need to do anything.
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
You don't need to do anything.
QUESTION 2a - Is the above correct?
The code is not correct. You're violating The Rule of Three. In particular, the automatically-generated MyDynamicPoint's copy constructor and assignment operator will make a bitwise copy of the points pointer. If you copy an instance of MyDynamicPoint, you'll end up with two object sharing the same points pointer:
When one of the objects goes of scope, the other becomes unusable.
When the second object goes out of scope, its destructor will attempt to free memory that's already been freed. This is undefined behaviour.
I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
No, it does not mean that. In fact, you should probably continue to store objects by value. However, you do need to fix the rule of three.
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Since you have a list of raw pointers, the destructors will not be called automatically. The easiest way to fix that is to either store objects by value, or use std::unique_ptr or std::shared_ptr instead of raw pointers.
To question 1, there is nothing you need to do. As you store the objects by value the compiler and the library will handle everything.
However, when you store pointer as in the second case, you need to delete those pointers that you have allocated with new, or you will have a memory leak.
And you have to delete the pointers before doing the erasing, as that can invalidate the iterator:
delete *it;
myList.erase(it);
I think following should work
MyPoint* ptr = myList.back();
delete ptr;
myList.pop_back();
OR
MyPoint* ptr = myList.back();
delete ptr;
myList.erase(ptr);

Is this the right way to write a destructor?

Besides a lot of member functions, my Graph class has 3 main members: a vector of pointers to its vertices, called "vertex", a vector of pointers to its edges, called "edge", and an integer counter variable. I started/attempted to write the destructor to deallocate the memory from the vectors, but I'm not sure if I am doing it correctly. And what do I do about the counter? I tried to say "delete counter," but it's not a pointer (oops).
Graph<Object,Weight>::~Graph(){
for(unsigned int i=0; i<vertex.size(); ++i){
delete vertex[i]; }
for(unsigned int j=0; j<edge.size(); ++j){
delete edge[j]; }
//counter?
}
Deleting depends on the way you allocated, see The difference between delete and delete [] in C++
As for your int member, since you didn't dynamically allocate it (you didn't use new) you don't have to delete it.
Assuming the type of vertex is std::vector<Vertex*> and you create the vector as follows:
vertex.push_back( new Vertex );
your clean up code looks correct.
But, I urge you not to do this. Declare vertex as std::vector<std::unique_ptr<Vertex>> and you don't need to worry about deleteing the individual vector members anymore.
If you're using Boost, you could also make vertex a boost::ptr_vector.
As for the counter variable, unless you're newing the counter somewhere during class construction, you don't need to delete it.
is counter a plain ordinary int variable? If so, you're not in charge of its lifetime.
The delete keyword is only to be used when you've created an object with the new keyword. (And even then, only when there isn't something else in your program, such as shared_ptr which is doing the delete for you)
When using new/delete you're taking over from the language and managing the lifetime/existance of an object yourself. ordinary variables are created and destroyed automatically, meaning you don't need to worry about them.
You can delete an array of pointers with:
del[] arr; // arr is array of pointers.
Whereas, if counter is from stack, the program will take care of it, and you as programmer don't need to worry about freeing that memory.
I'm assuming that vertex and edge are allocated using new? then what you have written is fine but if you declared your vertex and edge as an array and newed using new [] operator then you need to use the delete [] call instead of delete, if the counter was not declared as a pointer and newed then there is no need to delete the counter.
As a design decision you should consider declaring your vertex and edge objects as boost::shared_ptr or unique_ptr so that they are reference counted and when the Graph object goes out of scope they are automatically cleaned up so you don't even need to flesh out your destructor.
If you have c++11 then you can use the std versions and not need boost like std::shared_ptr and std::unique_ptr.

std::vector, constructors, objects

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.