I know that whenever I create a new object for a class, that object is stored in memory. I also know that in creating that object, it can only be accessed within the set of braces it is created in (Scope visibility). I need to find a way to delete that object outside of the braces it is created in. I have looked at smart pointers briefly, and it might be what I want to use? I'm assuming it is, I just don't know for sure. If a smart pointer can satisfy my needs, would someone please provide me with an example of how to use a smart pointer to access an object outside of where it has been created? Thanks :)
EDIT:
Example of what I'm trying to do:
class ModernWarfare2
{
//my class
ModernWarfare2();
};
DWORD XamHook(DWORD r3, DWORD r4, DWORD r5)
{
switch(XamGetCurrentTitleId())//a function that tells what game is being played
{
case Xbox360Dashboard://if i were to exit the game mw2
{
if(CODAllocated)//a boolean
{
//free the memory of the previous cod game
if(MW2Allocated)//another boolean
{
delete[] MW2;//gives me an error because i dont have access to MW2
}
}
break;
}
case COD_MW2:
{
if(!CODAllocated)
{
if(!MW2Allocated)
{
ModernWarfare2 *MW2 = new ModernWarfare2();
}
}
break;
}
}
return XamInputGetState(r3,r4,r5);
}
How do I fix my issue?
I also know that in creating that object, the object can only be accessed within the set of braces it is created in.
Not necessarily; that's only true when you construct objects with automatic storage duration, like this:
void foo()
{
T obj;
}
Such objects, yes, go out of scope.
Objects you allocate dynamically do not:
void foo()
{
T* obj = new T();
}
This is a memory leak because you never destroy *obj; however, you can access it from pretty much wherever you like:
T* foo()
{
return new T();
}
void bar()
{
T* obj = foo();
// yay!
}
or:
T* obj = nullptr;
void foo()
{
obj = new T();
}
void bar()
{
// do stuff with *obj
}
void baz()
{
foo();
bar();
}
This all gets dangerous and messy because you end up with spaghetti code in which the lifetime of the dynamically-allocated object is unclear, and in the examples above I still haven't approached the topic of eventually destroying the object. You have to be really careful not to destroy it whilst you're still using it.
This is where smart pointers come in, but if you want a tutorial on using smart pointers I'm going to have to refer you back to your C++11 book.
"I also know that in creating that object, the object can only be accessed within the set of braces it is created in." - This depends on how you create the object.
Example 1 (can't be accessed outside braces):
void func(void)
{
Object obj("foo", "bar");
}
Example 2 (can be accessed outside braces):
Object* func(void)
{
Object* obj = new Object("foo", "bar");
return obj;
}
Example 2 can be deleted using the keyword delete.
Take a look here for more information on pointers.
I haven't personally found a use for smart pointers but MSDN has good information on the topic here
By creating MW2 with
{
ModernWarfare2 *MW2 = new ModernWarfare2();
}
I was not able to reference MW2 elsewhere. By doing this, I can create it and delete it in two different spots:
class ModernWarfare2
{
//my class
ModernWarfare2();
};
ModernWarfare2 *MW2 = NULL;
DWORD XamHook(DWORD r3, DWORD r4, DWORD r5)
{
switch(XamGetCurrentTitleId())//a function that tells what game is being played
{
case Xbox360Dashboard://if i were to exit the game mw2
{
if(CODAllocated)//a boolean
{
//free the memory of the previous cod game
if(MW2Allocated)//another boolean
{
delete MW2;//gives me an error because i dont have access to MW2
}
}
break;
}
case COD_MW2:
{
if(!CODAllocated)
{
if(!MW2Allocated)
{
if(MW2 == NULL)
{
MW2 = new ModernWarfare2();
}
}
}
break;
}
}
return XamInputGetState(r3,r4,r5);
}
I think what you need is basic design pattern
Make the data and the functions members of a class
class SomeHandler
{
public:
void Acquire( /* some source */ );
void DoSomething( /* eventual parameters */ );
bool TrySomething(); // returns true if successful
private:
void internalFunction();
bool inGoodState;
SomeType dataINeed;
SomeOtherType otherData;
};
void SomeHandler::Acquire( /**/ )
{
// implement like this
}
now the functions can access the all the data
the use it like
int main()
{
SomeHandler h;
h.Acquire();
if( h.TrySomething() )
{
h.DoSomething();
}
}
Based on your code snippet, You have to save your pointer MW2 for
future so that you can delete the pointer.
I would suggest you to change
if(!MW2Allocated)
to
if(!MW2)
so that you don't have to create another variable for saving the reference to your allocated memory
Offcourse you have to move
ModernWarfare2 *MW2
to a larger scope (move it to the scope same as MW2Allocated) and initialize it to NULL.
Use "nullptr" instead of "NULL" if you are using C++11 supported compiler.
Also makesure you use
delete
instead of
delete[]
since this is not an array allocation
I don't think you can use smart pointers to skip saving your reference to the allocated memory,
since they are meant to make the memory deletion automatic or to make sure two deletion doesn't occur
for the same memory.
Refer to
http://www.codeproject.com/Articles/541067/Cplusplus-Smart-Pointers
for a good explanation about smart pointers
Related
I have the following situation.
FooClass* fooPointer = new FooClass();
int main() {
while (/*logic*/) {
if (fooPointer) {
// some logic
}
}
}
class FooClass {
void fooClass::fooMethod() {
if (/*logic*/) {
//logic
delete this;
}
}
}
So I am basically deleting the object. However on the next iteration It still enters the if statement in the main method (
if (fooPointer) {
// some logic
}
).
Why doesn't it recognize that the object has already been deleted with the null check?
Calling delete on an object usually is doing two things:
It calls the destructor
It frees the memory of the object
It does not set anything to null nor does it change the value of pointers in any other means. That's why your check doesn't work.
So if you want to go this way, you somehow have to null your pointer yourself.
I have a question regarding how to correctly delete structs and it's respective pointers declared inside.
I have extracted an example from a project i have running and it doesn't seem to work correctly, the code doesn't crash but it seems i have some "memory leaks". I'm not sure that is the right wording. The issue is that the values is not really reset and are kept in the memory next time i initiate a class.
Sudocode below:
Header:
ProgramHeader.h
class ClassA : public publicClassA
{
public:
ClassA(void);
virtual ~ClassA();
private:
struct ApStruct{
struct
{
float *refA[2];
float *refB[2];
float *pVarA;
} fR;
struct
{
float *refA[2];
float *refB[2];
float *pVarA;
} f1kHz;
};
ApStruct* GetApStruct;
}
Program:
Program.cpp
#include "ProgramHeader.h"
ClassA::~ClassA()
{
//EDIT i did a typo my looks like this:
//delete ApStruct; //Wrong code
delete GetApStruct; //Corrected - however still not working
}
main()
{
GetApStruct = new ApStruct();
//Do Code
}
Hope it all makes a bit sense,
EDIT:
I have updated one wrong line in the code - however the question still remains the same. I will have a look at below to understand before i implement a solution.
EDIT 24/10/2015
I have been trying out a few of the suggestions below and im not able to find a solution to my issue, i must admit i also have difficulties to narrow it down what could cause it.
My code is part of a DLL. The code wraps some source code im not in control of, and therefore i have limited options how i init using constructors and new on pointers.
The reason i still think i have memory leak issues is if i add a "magic float" in my code the output of my functions change, even the float is not used anywhere - it is just declared.
I get different results when:
Calling InitCode - once!
then i will call CallCode multiple time - doing my calculations
Destruct the instance of the class
When i repeat the above again i get different result from the first time i run the code but afterwards it stays the same.
If i include the magic line all seems to work???
Updated SudoCode:
Program.cpp
#include "ProgramHeader.h"
ClassA::~ClassA()
{
//EDIT i did a typo my looks like this:
//delete ApStruct; //Wrong code
delete GetApStruct; //Corrected - however still not working
}
main()
{
void initCode()
{
GetApStruct = new ApStruct();
float InitValue = 0.F
//Magic line:
float magicLine = 123456.f; //If this line is commented out i get different results in my code
//End Magic Line
fr.refA[0] = &InitValue;
fr.refA[0] = &InitValue;
fr.refA[0] = &InitValue;
fr.pVarA = &InitValue;
...
}
void CallCode()
{
float CallValue = 123.F
//Magic line:
float magicLine = 123456.f; //If this line is commented out i get different results in my code
//End Magic Line
fr.refA[0] = &CallValue;
fr.refA[0] = &CallValue;
fr.refA[0] = &CallValue;
fr.pVarA = &CallValue;
...
}
}
Thanks guys for you support,
Thomas
I would recommend something like the following for allocation and cleanup...
#include <iostream>
using namespace std;
class ClassA
{
public:
ClassA(void);
virtual ~ClassA();
private:
struct ApStruct {
struct
{
float *refA[2];
float *refB[2];
float *pVarA;
} fR;
struct
{
float *refA[2];
float *refB[2];
float *pVarA;
} f1kHz;
};
ApStruct* GetApStruct;
};
ClassA::ClassA(void) {
GetApStruct = new ApStruct{};
GetApStruct->fR.refA[0] = new float{ 1.f };
GetApStruct->fR.refA[1] = new float{ 2.f };
GetApStruct->fR.refB[0] = new float{ 3.f };
GetApStruct->fR.refB[1] = new float{ 4.f };
GetApStruct->fR.pVarA = new float { 0.f };
// do same for struct f1kHz
// ...
cout << "Construction" << endl;
}
ClassA::~ClassA()
{
if (GetApStruct != nullptr) {
if (GetApStruct->fR.refA[0] != nullptr) {
delete GetApStruct->fR.refA[0];
GetApStruct->fR.refA[0] = nullptr;
}
if (GetApStruct->fR.refA[1] != nullptr) {
delete GetApStruct->fR.refA[1];
GetApStruct->fR.refA[1] = nullptr;
}
if (GetApStruct->fR.refB[0] != nullptr) {
delete GetApStruct->fR.refB[0];
GetApStruct->fR.refB[0] = nullptr;
}
if (GetApStruct->fR.refB[1] != nullptr) {
delete GetApStruct->fR.refB[1];
GetApStruct->fR.refB[1] = nullptr;
}
if (GetApStruct->fR.pVarA != nullptr) {
delete GetApStruct->fR.pVarA;
GetApStruct->fR.pVarA = nullptr;
}
// do same for struct f1kHz
// ...
// finally
delete GetApStruct;
GetApStruct = nullptr;
}
cout << "Destruction" << endl;
}
int main() {
{
ClassA a;
}
system("pause");
return 0;
}
Well when you create a structure/class object, it holds the variables and pointers in that object memory area( say an object occupies some space in memory. Let's call it a box). Those pointer variables when initialized with new() or malloc(), are given space outside of that box in which the object's data resides. Those pointers now point to some memory area that is outside of that object's memory area. Now when the object is destructed, that space occupied by object (as we called it the box) is destroyed accompanying the pointer variables. The memory area pointed by the pointers is still in there in program/process memory area. Now we have no clue what's it address or where it lies. That's called memory leak. To avoid this situation, we need to de-allocate the memory referenced by pointers using delete keyword. We're free to go now. I tried to illustrate it with a simple graphic below. ObjectA box illustrates the area occupied by it in the memory. Note that this container/box holds the local varialbes including pointer. The pointer points to some memory location, say 0xFFF... and is illustrated by green line. When we destroy ObjectA, It simply destroys everything in it including 0xFFF address. But the memory located on 0xFFF is still allocated in the memory. A memory leak.
In your destructor, de-allocate memory explicitly using delete keyword. Whoa! We saved the memory.
From Wikipedia Resource Acquisition Is Initialization
Resource Acquisition Is Initialization (RAII) is a programming idiom used prominently in C++. In RAII, resource acquisition is done during object creation, by the constructor, while resource release is done during object destruction, by the destructor. If objects are destroyed properly, resource leaks do not occur.
So you can new the memory used for pointers in constructor and release them in destructor:
ClassA::ClassA(void) {
GetApStruct = new ApStruct;
GetApStruct->fR.refA[0] = new float{ 1.f };
GetApStruct->fR.refA[1] = new float{ 2.f };
}
ClassA::~ClassA(void) {
delete []GetApStruct->fR.refA;
delete GetApStruct;
}
Alright, let me be direct:
If you are using new or delete, you are doing it wrong.
Unless you are an experienced user, or you wish to implement a low-level side project, do not ever use new and delete.
Instead, use the existing standard classes to handle memory ownership, and just avoid heap-allocation when it is unnecessary. As a bonus, not only will you avoid memory leaks, but you will also avoid dangling references (ie, using memory after deleting it).
class ClassA : public publicClassA {
public:
private:
struct ApStruct{
struct
{
float refA[2];
float refB[2];
float pVarA;
} fR;
struct
{
float refA[2];
float refB[2];
float pVarA;
} f1kHz;
};
ApStruct GetApStruct;
}
And yes, in your case it is as simple as removing the pointers. Otherwise, if you want dynamic arrays (ie, arrays whose length is unknown at compile-time) use std::vector.
Example:
bool isHeapPtr(void* ptr)
{
//...
}
int iStack = 35;
int *ptrStack = &iStack;
bool isHeapPointer1 = isHeapPtr(ptrStack); // Should be false
bool isHeapPointer2 = isHeapPtr(new int(5)); // Should be true
/* I know... it is a memory leak */
Why, I want to know this:
If I have in a class a member-pointer and I don't know if the pointing object is new-allocated. Then I should use such a utility to know if I have to delete the pointer.
But:
My design isn't made yet. So, I will program it that way I always have to delete it. I'm going to avoid rubbish programming
There is no way of doing this - and if you need to do it, there is something wrong with your design. There is a discussion of why you can't do this in More Effective C++.
In the general case, you're out of luck, I'm afraid - since pointers can have any value, there's no way to tell them apart. If you had knowledge of your stack start address and size (from your TCB in an embedded operating system, for example), you might be able to do it. Something like:
stackBase = myTCB->stackBase;
stackSize = myTCB->stackSize;
if ((ptrStack < stackBase) && (ptrStack > (stackBase - stackSize)))
isStackPointer1 = TRUE;
The only "good" solution I can think of is to overload operator new for that class and track it. Something like this (brain compiled code):
class T {
public:
void *operator new(size_t n) {
void *p = ::operator new(n);
heap_track().insert(p);
return p;
}
void operator delete(void* p) {
heap_track().erase(p);
::operator delete(p);
}
private:
// a function to avoid static initialization order fiasco
static std::set<void*>& heap_track() {
static std::set<void*> s_;
return s_;
}
public:
static bool is_heap(void *p) {
return heap_track().find(p) != heap_track().end();
}
};
Then you can do stuff like this:
T *x = new X;
if(T::is_heap(x)) {
delete x;
}
However, I would advise against a design which requires you to be able to ask if something was allocated on the heap.
Well, get out your assembler book, and compare your pointer's address to the stack-pointer:
int64_t x = 0;
asm("movq %%rsp, %0;" : "=r" (x) );
if ( myPtr < x ) {
...in heap...
}
Now x would contain the address to which you'll have to compare your pointer to. Note that it will not work for memory allocated in another thread, since it will have its own stack.
here it is, works for MSVC:
#define isheap(x, res) { \
void* vesp, *vebp; \
_asm {mov vesp, esp}; \
_asm {mov vebp, ebp}; \
res = !(x < vebp && x >= vesp); }
int si;
void func()
{
int i;
bool b1;
bool b2;
isheap(&i, b1);
isheap(&si, b2);
return;
}
it is a bit ugly, but works. Works only for local variables. If you pass stack pointer from calling function this macro will return true (means it is heap)
In mainstream operating systems, the stack grows from the top while the heap grows from the bottom. So you might heuristically check whether the address is beyond a large value, for some definition of "large." For example, the following works on my 64-bit Linux system:
#include <iostream>
bool isHeapPtr(const void* ptr) {
return reinterpret_cast<unsigned long long int>(ptr) < 0xffffffffull;
}
int main() {
int iStack = 35;
int *ptrStack = &iStack;
std::cout << isHeapPtr(ptrStack) << std::endl;
std::cout << isHeapPtr(new int(5)) << std::endl;
}
Note that is a crude heuristic that might be interesting to play with, but is not appropriate for production code.
First, why do you need to know this? What real problem are you trying to solve?
The only way I'm aware of to make this sort of determination would be to overload global operator new and operator delete. Then you can ask your memory manager if a pointer belongs to it (the heap) or not (stack or global data).
Even if you could determine whether a pointer was on one particular heap, or one particular stack, there can be multiple heaps and multiple stacks for one application.
Based on the reason for asking, it is extremely important for each container to have a strict policy on whether it "owns" pointers that it holds or not. After all, even if those pointers point to heap-allocated memory, some other piece of code might also have a copy of the same pointer. Each pointer should have one "owner" at a time, though ownership can be transferred. The owner is responsible for destructing.
On rare occasions, it is useful for a container to keep track of both owned and non-owned pointers - either using flags, or by storing them separately. Most of the time, though, it's simpler just to set a clear policy for any object that can hold pointers. For example, most smart pointers always own their container real pointers.
Of course smart pointers are significant here - if you want an ownership-tracking pointer, I'm sure you can find or write a smart pointer type to abstract that hassle away.
Despite loud claims to the contrary, it is clearly possible to do what you want, in a platform-dependent way. However just because something is possible, that does not automatically make it a good idea. A simple rule of stack==no delete, otherwise==delete is unlikely to work well.
A more common way is to say that if I allocated a buffer, then I have to delete it, If the program passes me a buffer, it is not my responsibility to delete it.
e.g.
class CSomething
{
public:
CSomething()
: m_pBuffer(new char[128])
, m_bDeleteBuffer(true)
{
}
CSomething(const char *pBuffer)
: m_pBuffer(pBuffer)
, m_bDeleteBuffer(false)
{
}
~CSomething()
{
if (m_bDeleteBuffer)
delete [] m_pBuffer;
}
private:
const char *m_pBuffer;
bool m_bDeleteBuffer;
};
You're trying to do it the hard way. Clarify your design so it's clear who "owns" data and let that code deal with its lifetime.
here is universal way to do it in windows using TIP:
bool isStack(void* x)
{
void* btn, *top;
_asm {
mov eax, FS:[0x08]
mov btn, eax
mov eax, FS:[0x04]
mov top, eax
}
return x < top && x > btn;
}
void func()
{
int i;
bool b1;
bool b2;
b1 = isStack(&i);
b2 = isStack(&si);
return;
}
The only way I know of doing this semi-reliably is if you can overload operator new for the type for which you need to do this. Unfortunately there are some major pitfalls there and I can't remember what they are.
I do know that one pitfall is that something can be on the heap without having been allocated directly. For example:
class A {
int data;
};
class B {
public:
A *giveMeAnA() { return &anA; }
int data;
A anA;
};
void foo()
{
B *b = new B;
A *a = b->giveMeAnA();
}
In the above code a in foo ends up with a pointer to an object on the heap that was not allocated with new. If your question is really "How do I know if I can call delete on this pointer." overloading operator new to do something tricky might help you answer that question. I still think that if you have to ask that question you've done something very wrong.
How could you not know if something is heap-allocated or not? You should design the software to have a single point of allocation.
Unless you're doing some truly exotic stuff in an embedded device or working deep in a custom kernel, I just don't see the need for it.
Look at this code (no error checking, for the sake of example):
class A
{
int *mysweetptr;
A()
{
mysweetptr = 0; //always 0 when unalloc'd
}
void doit()
{
if( ! mysweetptr)
{
mysweetptr = new int; //now has non-null value
}
}
void undoit()
{
if(mysweetptr)
{
delete mysweetptr;
mysweetptr = 0; //notice that we reset it to 0.
}
}
bool doihaveit()
{
if(mysweetptr)
return true;
else
return false;
}
~A()
{
undoit();
}
};
In particular, notice that I am using the null value to determine whether the pointer has been allocated or not, or if I need to delete it or not.
Your design should not rely on determining this information (as others have pointed out, it's not really possible). Instead, your class should explicitly define the ownership of pointers that it takes in its constructor or methods. If your class takes ownership of those pointers, then it is incorrect behavior to pass in a pointer to the stack or global, and you should delete it with the knowledge that incorrect client code may crash. If your class does not take ownership, it should not be deleting the pointer.
I have some legacy-era code at work that takes in a double-pointer and allocates memory to it. A shortened example of it would look something like this:
struct LegacyObj
{
int a;
double b;
};
void LegacyAllocator(LegacyObj** ppObj)
{
*ppObj = (LegacyObj*)malloc(sizeof(LegacyObj));
}
void LegacyDeleter(LegacyObj** ppObj)
{
free(*ppObj);
}
The actual LegacyAllocator function is ~100 lines and mixes reading from files with creating a linked list of LegacyObj pointers, and isn't something I'd be able to get away with rewriting right now. I would like, however, to make the use of this function a bit safer, avoiding any memory leaks that may occur from exceptions &tc. The first solution I came up with was to wrap it up in a class and handle calling the legacy functions in the ctor/dtor.
class RAIIWrapper
{
public:
RAIIWrapper()
:obj{nullptr}
{
::LegacyAllocator(&obj);
}
RAIIWrapper(RAIIWrapper&& that)
: obj{ that.obj}
{
that.obj = nullptr;
}
RAIIWrapper& operator=(RAIIWrapper&& that)
{
RAIIWrapper copy{std::move(that)};
std::swap(obj, copy.obj);
return *this;
}
~RAIIWrapper ()
{
::LegacyDeleter(&obj);
}
private:
LegacyObj* obj;
};
But I'm curious - is there a way to do this using std::shared_ptr or std::unique_ptr? I've not been able to come up with a solution without having to keep the original pointer passed to LegacyAllocator around.
Yes, you can use a custom deleter with std::unique_ptr or std::shared_ptr, for example:
struct Deleter {
void operator()(LegacyObj *p) const {
LegacyDeleter(&p);
}
};
std::unique_ptr<LegacyObj, Deleter> MakeLegacyObj() {
LegacyObj *p = 0;
LegacyAllocator(&p);
return std::unique_ptr<LegacyObj, Deleter>(p);
}
std::unique_ptr<LegacyObj, Deleter> p = MakeLegacyObj();
And, as correctly pointed out by #Dave, this works with shared_ptr too:
std::shared_ptr<LegacyObj> p = MakeLegacyObj();
You can use unique_ptr to delete the memory, but you'll have to provide a custom Deleter class since the memory is allocated using malloc rather than new.
Better yet, change the allocation code to use new instead and just use unique_ptr. If you go down this road you can just have the allocator return a unique_ptr instead of a pointer to the memory.
Assuming you need to provide your own custom deleter, here is one way you might do it:
template <typename T>
class MallocDeleter
{
public:
void operator() (T* obj) const
{
LegacyDeleter (*obj);
}
};
typedef std::unique_ptr <LegacyObj, MallocDeleter <LegacyObj>> unique_legacy_ptr;
You could also probably provide a make_unique_legacy type function which allocates by calling LegacyAllocator, instead of having to initialize the unique_ptr yourself.
You can create a factory function for unique_ptrs like this:
typedef void(* LegacyDeleterType)(LegacyObj*);
typedef std::unique_ptr<LegacyObj,LegacyDeleterType> UniqueLegacyPtr;
UniqueLegacyPtr makeUniqueLegacyObj()
{
LegacyObj * p = nullptr;
LegacyAllocator( &p );
return UniqueLegacyPtr( p, [](LegacyObj*p){ LegacyDeleter(&p); } );
}
You can now use that to create unique_ptrs and you can also assign to shared_ptrs which capture the custom deleter automatically at construction:
int main()
{
auto unique = makeUniqueLegacyObj();
std::shared_ptr<LegacyObj> shared = makeUniqueLegacyObj();
}
Say I have a pointer like this:
int *thingy;
At some point, this code may or may not be called:
thingy=new int;
How do I know if I can do this:
delete thingy;
I could use a bool for every pointer and mark the bool as true whenever the I use new, but I have many pointers and that would get very unwieldy.
If I have not called new on thingy, calling delete on it would likely cause a crash, right?
I searched around quite a bit but could find no answer that clearly fit my situation.
EDIT: I need to be able to delete the pointers as many times as I like without the pointers necessarily pointing to any data. If this is impossible I'll have to re-write my code.
Initialize it to NULL always
int *thingy = NULL;
and then
delete thingy;
thingy = NULL;
is valid even if thingy is NULL. You can do the delete as many times as you want as long as thingy is NULL delete will have no unwanted side effects.
There's no built-in way to tell if a particular pointer value is deleteable. Instead you simply have to design the program to do the right thing, preferably by carefully designing resource ownership policies in line with your requirements and them implementing them with something like RAII.
Given appropriate RAII types you will not need to scatter deletes or other resource management commands around your code. You will simply initialize and use objects of the appropriate types, and leave clean up to the objects themselves. For example if the RAII type unique_ptr corresponds to an ownership policy you want to use then you can manage an object this way:
unique_ptr<int> thingy {new int};
// use thingy ...
There's no need to manually cleanup, because unique_ptr takes care of that for you.
On the other hand if you try to manage resources directly you end up with lots of code like:
int *thingy = nullptr;
// ...
thingy = new int;
try {
// something that might throw
} catch(...) {
delete thingy;
thingy = nullptr;
throw;
}
delete thingy;
thingy = nullptr;
There is no builtin C++ tool to identify if a pointer points to heap data and can safely deleted. It's safe to delete a NULL pointer and you can set every pointer whose data has been deleted to NULL. But this doesn't help to differentiate between pointers to heap data and pointers to other data or to code.
When your operation system starts a process it will locate the code and data sections to specific data areas. In Windows this is partially controlled by the PE header of the EXE file. Therefore the actual address of the memory regions may vary. But you can identify where theses regions are located:
code
bss
data
stack
heap
After obtaining the address range for each region you can differentiate between a pointer to the heap data (where delete is appropriate) and a pointer to stack data. This allows you to differetiate between deleteable and data whose pointer you must not delete.
Write a wrapper class that does the tracking for you, eg:
template<typename T>
class ptr_t
{
private:
T* m_ptr;
bool m_delete;
ptr_t(const ptr_t&) {}
ptr_t& operator=(const ptr_t&) { return *this; }
public:
ptr_t()
: m_ptr(NULL), m_delete(false)
{
}
ptr_t(T *ptr, bool del)
: m_ptr(ptr), m_delete(del)
{
}
~ptr_t()
{
reset();
}
void assign(T *ptr, bool del)
{
if (m_delete)
delete m_ptr;
m_ptr = ptr;
m_delete = del;
}
void reset()
{
assign(NULL, false);
}
operator T*() { return m_ptr; }
bool operator!() const { return (!m_ptr); }
};
typedef ptr_t<int> int_ptr;
.
int_ptr thingy;
...
thingy.assign(new int, true);
...
thingy.reset();
.
int i;
int_ptr pi;
...
pi.assign(&i, false);
...
pi.reset();