I've often wondered,
I know I can create a pointer to an instance of an object at the same time as passing that same pointer as an argument to a function, using the new
keyword. Like I have below in the Animation::newFrame
function, given in the example below.
However, I'm also aware that as a general rule I'm responsible for calling delete
on things that I create using new
.
So when I call Frame's constructor like so:
Frame* myFrame
= new Frame(new point(0,0), new point(100,100), new point(50,20));
Where does the responsibility to eventually free the memory for the 3 points I have created using new
in the above function call lie?
After all, the above 3 new points don't exactly have names for me to call delete
on.
I've always sort-of assumed that they belong in the scope of the function they're called in, and they will simply go out of scope with the function. However, lately I've been thinking maybe that is not so.
I hope I've been clear enough here.
Thanks in advance,
Guy
struct Frame
{
public:
point f_loc;
point f_dim;
point f_anchor;
//the main constructor:: Creates a frame with some specified values
Frame(point* loc, point* dim, point* anchor)
{
f_loc = loc;
f_dim = dim;
f_anchor = anchor;
}
};
struct Animation
{
public:
vector<Frame*> frameList;
//currFrame will always be >0 so we subtract 1
void Animation::newFrame(int &currFrame)
{
vector<Frame*>::iterator it;//create a new iterator
it = frameList.begin()+((int)currFrame);//that new iterator is
//add in a default frame after the current frame
frameList.insert(
it,
new Frame(
new point(0,0),
new point(100,100),
new point(50,20)));
currFrame++;//we are now working on the new Frame
}
//The default constructor for animation.
//Will create a new instance with a single empty frame
Animation(int &currFrame)
{
frameList.push_back(new Frame(
new point(0,0),
new point(0,0),
new point(0,0)));
currFrame = 1;
}
};
EDIT: I forgot to mention that this question is purely theoretical. I am aware that there are much better alternatives to raw pointers such as smart pointers. I'm asking simply to deepen my understanding of regular pointers and how to manage them.
Also the example above is taken from a project of mine that is actually C++/cli and c++ mixed (managed and unmanaged classes), so that is why the contructor only accepts point*
and not passing by value (point
). Because point
is an unmanaged structure, and therefore when used within managed code, must be managed by myself, the programmer. :)
Deleting a pointer (or deleting what it points to, alternatively) means delete p; delete[] p; // for arrays. p was allocated prior to that statement like p = new type; It may also refer to using other ways of dynamic memory management, like free free(p); which was previously allocated using malloc or calloc.
To make use of smart pointers in a program, you will need to include the <memory> header file. Smart pointers perform automatic memory management by tracking references to the underlying object and then automatically deleting that object when the last smart pointer that refers to that object goes away.
The address of the pointer does not change after you perform delete on it. The space allocated to the pointer variable itself remains in place until your program releases it (which it might never do, e.g. when the pointer is in the static storage area).
You don't need to delete it, and, moreover, you shouldn't delete it. If earth is an automatic object, it will be freed automatically. So by manually deleting a pointer to it, you go into undefined behavior. Only delete what you allocate with new .
Clarifying and, often, enforcing the semantics of resource ownership is the responsibility of the programmer. This can be tricky business, especially when dealing with raw pointers as you are here, in an environment where resource ownership hasn't been given any real design consideration. The latter is prevalent not only in toy programs written by rookie programmers, but in production systems written by people with decades of experience who should have known better.
In your actual case above, the Frame
object must itself be responsible for delete
ing the 3 pointers passed in, and whatever constructed the Frame
itself must be responsible for delete
ing that.
Because resource ownership is such a minefield, programmers long ago invented a number of techniques to clarify the semantics of ownership, and make it much more difficult to introduce bugs and leaks by careless programmers. These days, in C++ it is considered a best-practice to avoid raw pointers and, in fact, dynamic allocation altogether whenever possible -- in major part because resource ownership is such a dangerous minefield.
In C++, the primary idiom used to accomplish these goals is RAII and the main tools used are auto_ptr
(C++03), unique_ptr
, shared_ptr
and their ilk. Boost also provides a number of so-called "smart pointers". Many of these parallel those found in C++11 (in fact, the new smart pointers in C++11 were initialliy developed by Boost), but there are also some that go beyond, such as intrusive_ptr
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With