shared_ptrs and the rule of three - c++

I am continuing my process of understanding these topics, and I wanted to try to actually use my knowledge on a class that I already had created previously called ArrayList, which dynamically allocates memory when the original array created when the class is created gets filled up. This is what (part of) my class looks like: [I guess most of the code itself isn't important, I'm just showing what I have. The main point of the question is after all the code]
And here are the functions that take care of adding elements to the array and reallocating memory when it gets filled up. The append function might look at bit weird because I'm trying to place the elements in ascending order, but that part's not really important.
Now that I've posted that class that took a lot more space than expected, here is my question:
How exactly would I use shared_ptrs with this class? I know that shared_ptrs make it easier to manage my dynamically allocated resources, but would a shared_ptr in this case be used to create the original array, and to delete the old array automatically when the pointer to the array is assigned to the new array? I can see how I would do that, but how would that have any effect on the rule of three [which I read basically is not needed if you use shared_ptrs]. I almost feel like..there are two dimensions to using shared_ptr in this case; one used to actually take care of allocating and deallocating resources for the object itself, but another also if I wanted to create a new object and copy the original object's array into the second object...if this makes sense? I'm guessing to do that I would have
ArrayList AL(10);
shared_ptr<ArrayList> ptr = make_shared<ArrayList>(AL);
Is this effectively doing the same thing as if I had done
ArrayList AL(10);
ArrayList AL2(AL);
except that it does the job of the destructor, copy constructor, and copy-assignment operator by itself? Sorry if this was all confusing and long but I'm just...confused.

I wouldn't use std::shared_ptr in your case. Since there's always only one owner, I'd prefer std::unique_ptr. It essentially works the same way, but it won't do the reference counting (since there's always only one owner holding the resource).
You'd no longer have to delete arr in your destructor and you'd modify the following lines:
delete [] arr;
arr = new int[that.size];
to something as simple as this:
arr.reset(new int[that.size]);
This will free the previous instance (if any) and then take ownership of the new one.

Related

Dynamic Pointers and Objects

I have to write an application to complete an assignment, at school. To do so, we have to create a dynamic array. My question is:
If I create a structure containing a dynamic pointer, and copy it, does the memory get copied too?
For instance:
struct SomePointerStruct
{
int* p_array;
}
What happens if I copy that structure? Also,
Do I need to clean up the original pointer?
By default, objects in c++ are copied byte-by-byte. that means that the pointer will be copied, and you will get two pointers pointing to the same array.
To fix this, you need to implement a copy constructor and should also override the operator=. Also, you may want to delete this array when you finish, so implement also a destructor. That is "the rule of three".
If I create a structure containing a dynamic pointer, and copy it,
does the memory get copied too?
No.
Much of the design of the C++ language is dictated by the edict, "You don't pay for what you don't need." One way this plays out is if you want to deep-copy something, you have to do it yourself.
Do I need to clean up the original pointer?
In general, yes.
For every new, there must be exactly one matching delete. If you instantiate a SomePointerStruct, and the construction of that calls new, that's one delete you need somewhere -- probably in SomePointerStruct's destructor. If you create a copy of SomePointerStruct and the copy deep-copies the original pointer (calling new), then that's a second delete you need -- again, probably in the destructor.
To avoid repeating the whole chapter named Memory from your C++ book, I'll answer with that:
Raw pointers shouldn't own memory.
By consequence:
struct SomePointerStruct { int x; }
is trivially copyable, and:
struct SomePointerStruct { std::unique_ptr<int> x; }
is noncopyable (but it's moveable). That extends to all of your other types (if they are properly constructed), sans the "trivially", perhaps. The fact that the pointer value would be copied in your original example would of course lead to a lot of problems, but since they can be easily avoided by using what I wrote above, it's kind of off the scope WRT such a simple assignment.
A whole another thing would be a non-owning pointer case, in which a copied struct would, of course, point to the same region of memory. You lose all the guarantees of the pointer pointing to a valid location, though, so a reference would be preferred.
As for creating of a dynamic array, you'd be best off with simply using std::vector.

Handle memory, garbage collector like

I have a piece of code that does a lot of memory allocation.
I would like to know if there were a pattern that I can implement to reuse previously deleted memory (because I build a lot of temporary objects that allocate memory like int*, char*, etc.. but it can be very huge).
My purpose is optimization, so I'd like to reuse the memory and not "delete" it even when using temporary object.
It may not be clear enough, let me know so that I can post some code to show you the problem.
Delegate the creation of your temporary objects to a class.
As pointed by Dan, you need to implement a memory manager Or Pool by overloading new and delete operators in that class.
Allocate big chunk of memory when first time new is called and divide that into fixed size blocks. Keep using these blocks for temporary objects.
When delete is called, just update the allocation status of that block.
Delete the big chunk once you are done with using temporary objects.
All I do is make sure the object has a spare pointer in it.
Then instead of "delete" I just keep a linked list of previously used objects, and push it on the front of the list.
Instead of "new" I pop one off.
If the list is empty, that's when I make a truly new one.

A destructor - should I use delete or delete[]?

I am writing a template class that takes as an input a pointer and stores it. The pointer is meant to point to an object allocated by another class, and handed to the this containing class.
Now I want to create a destructor for this container. How should I free the memory pointed to by this pointer? I have no way of knowing a priori whether it is an array or a single element.
I'm sort of new to C++, so bear with me. I've always used C, and Java is my OO language of choice, but between wanting to learn C++ and the speed requirements of my project, I've gone with C++.
Would it be a better idea to change the container from a template to a container for an abstract class that can implement its own destructor?
If you don't know whether it was allocated with new or new[], then it is not safe to delete it.
Your code may appear to work. For example, on one platform I work on, the difference only matters when you have an array of objects that have destructors. So, you do this:
// by luck, this works on my preferred platform
// don't do this - just an example of why your code seems to work
int *ints = new int[20];
delete ints;
but then you do this:
// crashes on my platform
std::string *strings = new std::string[10];
delete strings;
You must document how this class expects to be used, and always allocate as expected. You can also pass a flag to the object specifying how it should destroy. Also look at boost's smart pointers, which can handle this distinction for you.
Short answer:
If you use [] with new you want to use [] with delete.
//allocate some memory
myObject* m = new myObject[100];
//later on...destructor...
delete m; //wrong
delete[] m; //correct
That was the bare bones, the other thing you could look at is boost. Also quite difficult to answer considering you are not sure if its an array or single object. You could check this though via a flag telling your app whether to use delete or delete[].
As a general development rule, you should stick to a design where the class which calls new should also call delete
You shouldn't delete it at all. If your class takes an already initialized pointer, it is not safe to delete it. It might not even point to an object on the heap; calling either delete or delete[] could be disastrous.
The allocation and deallocation of memory should happen in the same scope. Which ever code owns and initializes the instance of your class is also presumably responsible for initializing and passing in the pointer, and that is where your delete should be.
Use delete if you allocated with new.
Use delete[] if you allocated with new[].
After these statements, if you still have a problem (maybe you want to delete an object that was created by someone else), then you are breaking the third rule:
Always delete what you created. Corollary, never delete what you did not create.
(Moving my comment into an answer, by request.)
JonH's answer is right (about using array destruction only when you used array construction), so perhaps you should offer templates: one for arrays, one not.
The other answer is to avoid arrays and instead expect a single instance that may or may not be a proper collection that cleans up after itself, such as vector<>.
edit
Stealing blatantly from Roger Pate, I'll add that you could require the use of a smart pointer, which amounts to a single-item collection.
If you have a class that takes a pointer it's going assume ownership of, then the contract for the use of the class needs to include one of a couple things. Either:
the interface needs to indicate how the object the pointer is pointing to was allocated so the new owner can know how to safely deallocate the object. This option has the advantage of keeping things simple (on one level anyway), but it's not flexible - the class can't handle taking ownership of static objects as well as dynamically allocated objects.
or
the interface needs to include a mechanism where a deallocation policy can be specified by whatever is giving the pointer to the class. This can be as simple as providing a mechanism to pass in a functor (or even a plain old function pointer) that will be called to deallocate the object (preferably in the same function/constructor that passes in the pointer itself). This makes the class arguably more complicated to use (but having a default policy of calling delete on the pointer, for example, might make it as easy to use as option 1 for the majority of uses). Now if someone wants to give the class a pointer to a statically allocated object, they can pass in a no-op functor so nothing happens when the class wants to deallocates it, or a functor to a delete[] operation if the object was allocated by new[], etc.
Since pointer in C++ does not tell us how it was allocated, yes, there's no way to decide what deallocation method to use. The solution is to give the choice to the user that hopefully knows how the memory was allocated. Take a look at Boost smart ptr library, especially at shared_ptr constructor with second parameter, for a great example.
A smart pointer like boost shared_pointer already has this covered, could you use it? linky
Put simply, given only a pointer to dynamically allocated memory there is no way of determining how to de-allocate it safely. The pointer could have been allocated in any of the the following ways:
using new
using new []
using malloc
using a user defined function
etc.
In all cases before you can deallocate the memory you have to know how it was allocated.

c++ vector of class object pointers

What I am trying to do is essentially create two vectors of objects, where some objects are entered into both lists and some are just entered into one. The first problem I found was that when I used push_back() to add an object into both lists the object was copied so that when I changed it from one list the object did not change in the other. To get around this I tried to create a list of pointers to objects as one of the lists. However when I accessed the pointer later on the data seemed to be corrupted, the data member values were all wrong. Here are some snippets of my code:
Definition of vectors:
vector<AbsorbMesh> meshList;
vector<AbsorbMesh*> absorbList;
...
Adding an object to both:
AbsorbMesh nurbsMesh = nurbs.CreateMesh(uStride, vStride);
// Add to the absorption list
absorbList.push_back(&nurbsMesh);
// Store the mesh in the scene list
meshList.push_back(nurbsMesh);
Accessing the object:
if (absorbList.size() > 0)
{
float receivedPower = absorbList[0]->receivedPower;
}
What am I doing wrong?
There's some details missing, but at a guess.
nurbsMesh goes out of scope between the push_back and the absorbList[0]->receivedPower.
So now your vector of pointers contains a pointer to an object that doesn't exist anymore.
Try adding a copy constructor to your AbsorbMesh class and adding to your vector like this.
absorbList.push_back(new AbsorbMesh(nurbsMesh));
meshList.push_back(nurbsMesh);
don't forget to delete the objects in absorbList, like this
for(vector<AbsorbMesh*>::iterator it = absorbList.begin(); it != absorbList.end(); it++) {
delete it;
}
Or store a shared pointer in your vector instead of a bare pointer. Boost has a good shared pointer implementation if you're interested. See the docs here
If you want to have updates to items in one vector modify objects in the other vector, then you'll need to store pointers in both vectors.
Using your original requirements (updating an item in one vector affects items in the other vector, here's how I'd do it with a boost shared pointer. (WARNING, untested code)
vector<boost::shared_ptr<AbsorbMesh> > meshList;
vector<boost::shared_ptr<AbsorbMesh> > absorbList;
boost::shared_ptr<AbsorbMesh> nurb = new AbsorbMesh(nurbs.CreateMesh(uStride, vStride));
meshList.push_back(nurb);
absorbList.push_back(nurb);
...
...
if (absorbList.size() > 0)
{
float receivedPower = absorbList[0].get()->receivedPower;
}
You are storing the address of an object allocated on stack. The nurbsMesh object gets destroyed as soon as your method which does push_back() ends. If you try to access this pointer afterwards the object is already destroyed and contains garbage. What you need is to retain the object which remains even after the function goes out of scope. To do this allocate the memory for the object from heap using new. But for every new you should have a corresponding delete. But in your case you'll have problems deleting it as you are pushing the same pointer into two vectors. To solve this, you would require some type reference counting mechanism.
Object is deleted when you try get pointer from vector.
Try do
vector.push_back(new Object);
Once you have fixed the problem that others mentioned (storing a pointer to an object that's on the stack), you're going to run into another issue. A vector may reallocate, which results in its contents moving to another location.
The safe way to do this, then, is to store pointers in both vectors. Then, of course, you need to ensure that they get deleted... but that's C++ for you.
absorbList.push_back(&nurbsMesh); is wrong
absorbList save pointer to local object. When nurbMesh is destroyed you can not write
absorbList[0]->
However when I accessed the pointer later on the data seemed to be corrupted
When you put something on a vector, the vector might move it from one physical location to another (especially e.g. when the vector is resized), which invalidates any pointer to that object.
To fix that, you'll need to store a pointer (possibly a 'smart pointer') in both vectors (instead of having one vector contain the object by value).
If you're going to do this, it might be a good idea to disable the object's copy constructor and assignment operator (by declaring them as private, and not defining them) to ensure that after an object is created it cannot be moved.
There are several things wrong with your example
AbsorbMesh nurbsMesh = nurbs.CreateMesh(uStride, vStride);
This object is allocated on the stack. It is a purely local object. This object is going to be destroyed when you reach the end of the current block surrounded by {}.
absorbList.push_back(&nurbsMesh);
Now you get the pointer to the object that most likely will be destroyed.
meshList.push_back(nurbsMesh)
And this copies an entirely new object on the vector.
It is equally wrong to push the object on the vector first and then push a pointer to the object on the vector using absorbList.push_back( &meshList.back() ) because vector::push_back will reallocate the whole vector, invalidating all pointers.
You might be able to create all AbsorbMesh objects first, push them onto a vector, and then get the pointers to these objects in the vector. As long as you don't touch the vector, you'll be fine.
Alternatively, create objects on the heap using new AbsorbMesh() but make sure to call delete on each pointer thus created. Otherwise you have a memory leak.
Third solution, avoid the trouble and use smart pointers that take care of object destruction for you.
First, as everybody else points out, you can't allocate objects on the stack (i.e., other than by new or something similar), and have them around after leaving the scope.
Second, having objects in an STL container and maintaining pointers to them is tricky, since containers can move things around. It's usually a bad idea.
Third, auto_ptr<> simply doesn't work in STL containers, since auto_ptrs can't be copied.
Pointers to independently allocated objects work, but deleting them at the right time is tricky.
What will probably work best is shared_ptr<>. Make each vector a vector<shared_ptr<AbsorbMesh> >, allocate through new, and at a slight cost in performance you avoid a whole lot of hassle.

Should I delete vector<string>?

I've painfully learned during last few days a lot about programming in c++.
I love it :)
I know I should release memory - the golden "each malloc=free" or "each new=delete" rules exist now in my world, but I'm using them to rather simple objects.
What about vector ? Wherever I can, I'm using vector.clear() but that clearly isn't enough, because I'm having huge memory leaks.
Could you guide me on how should I treat this thing?
*Edit
Thanks, your comments made me think about the alghorithm of this application and I'll be able to eliminate the vector totally. :O
Sorry - I started explaining what is my use case here and I found out what I really need. It's like that when you code last 3 days for 18 hours a day :|
*Edit 2
This is crazy. By small changes in code, I've eliminated memory usage from 2x130 mb (constantly growing) into 2x 13,5mb, constant size. Thanks for making me think about that in another way.
Btw. such self code review got a name - anyone remember that? It's when you ask anyone (even your mother or dog) and start explaining what's your problem - and suddenly you solve this 5 hour problem yourself, just by trying to look at it from other point of view, or just by trying to summarize what's it all about. I often find myself being catched on that...
The rule is that when you clear a vector of objects, the destructor of each element will be called. On the other hand, if you have a vector of pointers, vector::clear() will not call delete on them, and you have to delete them yourself.
So if all you have is a vector of strings, and not pointers to strings, then your memory leaks must be caused by something else.
You don't need to be doing this. std::string cleans itself up, so the strings are not your problem. Remember that YOU didn't use new so YOU don't have to use delete.
You should probably learn about RAII - it makes allocation and deallocation much simpler. You'll avoid memory leaks this way.
Calling v.clear() will destroy all objects that are currently held inside v, but it will not release the memory (it is assumed that the vector will soon be filled again).
If you really want to free the memory, the idiom is
vector<string>().swap(v);
This will create a new (temporary) vector and swap its contents with v. The temporary vector is then destroyed, freeing the memory along with it.
Deleting elements from STL containers is guaranteed to call destructors on these elements.
However, if you have a container of some pointer-to-T type, then you still have to free the pointed-to memory yourself (in this case, the "destructor" for the pointer gets called, which is a no-operation).
If you do not want to manually manage memory in this case, consider using a smart-pointer solution or a pointer container.
The vector (like all standard containers) owns the objects inside it.
So it is responsible for destroying them.
Note: If you vector contains pointers then it owns the pointers (not what the pointers point at). So these need to be deleted. But there are easier ways.
You could use a vector of smart pointers. In fact you should be using some form of smart pointer for nearly everything. If you are using pointers you are probably still programming like a C programmer.
So:
std::vector<int> data; // clear is fine.
std::vector<int*> data1; // Now things need to be deleted.
// alternative 1:
std::vector<boost::shared_ptr<int> > data2; // The shared pointer will auto
// delete the pointer.
// alternative 2:
boost::ptr_vector<int> data3; // Here the container knows that
// it is holding pointers and will
// auto de-reference them when you
// its members.
But it sounds like you need to start thinking about learning about smart pointers.
int* x = new int(5);
// Do stuff.
*x = 8;
delete x;
// --- Instead use a smart pointer:
std::auto_ptr<int> x(new int(5));
// Do stuff.
*x = 8;
// No delete (the auto ptr handles it.
If you have a vector and it goes out of scope, all objects in the vector are destroyed. There isn't really a need to call clear() unless you want to dump the contents and reuse the vector.
However if you by any chance are using something like a vector then the destructor of the objects being pointed to will not be called as the vector destructor doesn't follow the indirections represented by the pointers.
All that said, have you actually confirmed that you've got genuine memory leaks and that they are caused by the data in the vector?
Give a use case. The destructor on the string is getting called by vector::clear. Your problem lies elsewhere my friend.
also check out:
Does std::vector.clear() do delete (free memory) on each element?
As rlbond suggested, use RAII.
It's a good rule of thumb to never put new and delete calls into your main code flow. Always try to put them into objects so that the object destructor can free what needs to be freed. In this way, you avoid needing to remember to call delete and it makes your code exception safe (assuming that you make your object's operations exception safe).
For example, if you had a vector of pointers to STL strings or C-style character arrays, put that into a StringContainer (use a better name) and have the StringContainer hold a vector and in the StringContainer destructor run a for loop to delete each string in the vector.
You can make the vector inside the StringContainer a public member and mess around with it directly, but it's even better design to make it private or protected and add some member functions to manage the string* vector.
So your main C++ program should never see a new or delete anywhere. Instead it should have a lot of stack allocated objects, auto_ptrs and shared_ptrs.