auto_ptr sounds some freaky kind of. But don’t think wrong, it is very useful in programming actually very useful. Now what are auto_ptr?
Auto pointer comes with STL's standard namespace. auto_ptr is a template class created for encapsulating any dynamically created object majorly using new operator. They acts as a container for dynamically created objects on the free space, once you allocate a memory block you need not really care about deallocating memory because auto pointer takes care of freeing that memory area once the object goes out of scope.
Better we take a look over an example first,
int someFunc(){
T* pointer =
newT; // generic allocation of type T
/*
* your code
*/
delete
pointer; // lets free that memory
return some_value;
}
This code works very well if it doesn't do anything unusual. What if
someFunc
never executes the delete statement, say because of a condition which causes the control to go back to the caller as a result of the function return or because of an exception thrown during the execution of the function. This kind of situation causes our famous enemy memory leaks.The first question that will came is how to deal with this situations. The answer to this problem is auto pointer (auto_ptr), we can just wrap the pointer declared in the code above into a smart pointer that is auto pointer object and forget about the memory leak problems. Now even if the code execution doesn’t reach to the delete statement we can make sure that the memory pointed by pointer variable gets cleaned up when the function’s stack unwinds.
Here is the corrected
someFunc declared again,
#include <iostream>
#include <memory.h>
usingnamespace
std;
int someFunc ()
{
T* pointer =
newT; // generic allocation of type T
/*
* your code
*/
// destructor gets called as the object goes out of scope
return some_value;
}
In the above code we need not even have to explicitly call delete on the pointer. The auto pointer automatically frees up the memory of the contained object on destruction.
Using an auto_ptr is just the same as using built-in pointer, and to "give back" the resource we just call release():
class CSomeClass {
private:
int
m_nValue;
public:
CSomeClass () {
m_nValue =
0;
}
CSomeClass (
intnValue) {
m_nValue = nValue;
}
void
m_SetValue(
intnValue) {
m_nValue = nValue;
}
void
m_PrintValue() {
printf(
"m_nValue
: %d\n", m_nValue);
}
CSomeClass &
operator=(
intnValue) {
m_nValue = nValue;
return
*
this;
}
};
int someFunc () {
printf (“lets start with an object first\n”);
CSomeClass *myptr1 =
newCSomeClass ();
auto_ptr myptr2( myptr1 );
// passing to an auto_ptr
// use the auto_ptr same as pointer
*myptr2 =
12;
// same as "*myptr1 = 12;"
myptr2->m_PrintValue();
// same as myptr1->m_PrintValue();"
// get() to check the pointer value
assert( myptr1 == myptr2.get() );
// release() to return to original pointer
CSomeClass * myptr3 = myptr2.release();
// delete the object as no auto_ptr here now
delete
myptr3;
return some_value;
}
We can use reset() function to reset the auto_ptr to take a different object. If the auto_ptr already has an object, then first it deletes the that object.
int someFunc () {
auto_ptr aptr(
newCSomeClass (
10) );
aptr.reset(
newCSomeClass (
20) );
// deletes the first
CSomeClass
that was
// allocated with "new
CSomeClass
(10)"
}
// aptr goes out here
// the secondCSomeClass
is also deleted
class CSomeClass {
public:
CSomeClass () {
m_pHisName = NULL;
}
~ CSomeClass () {
delete
[] m_pHisName;
}
void
m_SetupHisName(
intnSize) {
m_pHisName =
newchar
[nSize];
}
void
m_SetHisName(
char* pHisName) {
strcpy(m_pHisName, pHisName);
}
char
* m_GetHisName() {
return
m_pHisName;
}
private:
char
* m_pHisName;
};
class CSomeEmp {
public:
CSomeEmp () {
m_ptrHisName =
newCSomeClass ();
}
~ CSomeEmp () {
delete
m_ptrHisName;
}
void
m_Name(
char* pName) {
/*
*
Runtime Exception: allocate memory before setting
*
name by using syntax m_ptrHisName->m_SetupHisName(<size>);
*/
m_ptrHisName->m_SetHisName(pName);
}
void
m_PrintHisName() {
printf(
"Name: %s\n",m_ptrHisName->m_GetHisName());
}
private:
CSomeClass * m_ptrHisName;
};
void someOutsideFunction()
{
CSomeEmp objEmp;
objEmp.m_Name(
"Saurav");
// Exception Here
objEmp.m_PrintHisName();
}
Its certain that the program execution stops whenever an exception occurs, if you notice the code carefully there is a memory leak in there as class
CSomeEmp
creates
CSomeClass
instance using operator new in its constructor. This allocated memory never gets freed up as the code execution never reaches upto this point. We can certainly make the memory allocation exception safe by encapsulating the
CSomeClass
pointer into an auto_ptr object, Let’s correct the
CSomeEmp class now,
class CSomeEmp {
public:
CSomeEmp () {
m_ptrHisName = auto_ptr(
newCSomeClass ());
}
~ CSomeEmp () {
CSomeClass * scptr = m_ ptrHisName.release();
delete
scptr;
}
void
m_Name(
char* pName) {
/*
*
Runtime Exception: allocate memory before setting
*
name by using syntax m_ptrHisName->m_SetupHisName(<size>);
*/
m_ptrHisName->m_SetHisName(pName);
}
void
m_PrintHisName() {
printf(
"Name: %s\n",m_ptrHisName->m_GetHisName());
}
private:
auto_ptr m_ptrHisName;
};
The code above creates a auto_ptr object member of
CSomeEmp
class. By this we ensure that the memory contained by the m_ptrHisName object gets frees up even in case an exception occurs.
No comments:
Post a Comment