I'm using a library that, in order to construct some object that I use, expects a raw pointer to an object. I'm not sure what it will do with the pointer, to make my code as safe as possible, what should I pass to this function?
Use a unique pointer - if they decide to delete the pointer, I will do a double-delete
Keep track of a raw pointer - bad because I have to remember to write delete, but it could still be a double-delete
Use auto duration and give them a pointer Give them a reference - their code will error if they call delete
Use a shared pointer - same double-delete problem as unique pointer, but now my scope won't hurt their pointer
Based on my reading, option 3 seems like what I should do - they shouldn't be calling delete on the pointer, and this format enforces that. But what if I don't know whether they now or in the future will call delete on the reference I gave them? Use a shared pointer and say "not my fault about the double delete"?
#include <memory>
#include <iostream>
class ComplexObj {
public:
ComplexObj() : m_field(0) {}
ComplexObj(int data) : m_field(data) {}
void print() { std::cout << m_field << std::endl; }
private:
int m_field;
};
class BlackBox {
public:
BlackBox(ComplexObj* data) {
m_field = *data;
// Do other things I guess...
delete data;
std::cout << "Construction complete" << std::endl;
}
void print_data() { m_field.print(); }
private:
ComplexObj m_field;
};
int main(int argc, char* argv[]) {
// Use a smart pointer
std::unique_ptr<ComplexObj> my_ptr(new ComplexObj(1));
BlackBox obj1 = BlackBox(my_ptr.get());
obj1.print_data();
my_ptr->print(); // Bad data, since BlackBox free'd
// double delete when my_ptr goes out of scope
// Manually manage the memory
ComplexObj* manual = new ComplexObj(2);
BlackBox obj2 = BlackBox(manual);
obj2.print_data();
manual->print(); // Bad data, since BlackBox free'd
delete manual; // Pair new and delete, but this is a double delete
// Edit: use auto-duration and give them a pointer
ComplexObj by_ref(3);
BlackBox obj3 = BlackBox(&by_ref); // they can't call delete on the pointer they have
obj3.print_data();
by_ref.print();
// Use a shared pointer
std::shared_ptr<ComplexObj> our_ptr(new ComplexObj(4));
BlackBox obj4 = BlackBox(our_ptr.get());
obj4.print_data();
our_ptr->print(); // Bad data, they have free'd
// double delete when our_ptr goes out of scope
return 0;
}
Other questions I read related to this topic...
unique_ptr.get() is legit at times
I should pass by reference
I think I am case 2 and should pass by reference
You cannot solve this problem with the information you have. All choices produce garbage.
You have to read the documentation of the API you are using.
Doing any of your 4 answers without knowing if they take ownership of the pointer will result problems.
Life sometimes sucks.
If you have a corrupt or hostile API, the only halfway safe thing to do is to interact with it in a separate process, carefully flush all communication, and shut down the process.
If the API isn't corrupt or hostile, you should be able to know if it is taking ownership of the pointed to object. Calling an API without knowing this is a common mistake in novice C++ programmers. Don't do it. Yes, this sucks.
If this API is at all internal and you have any control, seek to make all "owning pointer" arguments be std::unique_ptr<>s. That makes it clear in the API that you intend to own the object and delete it later.
Related
The question:
I have some code executing which is very unsafe. My question is, does this code trigger undefined behavior or is it 'correct' (= behavior fully defined).
Some context:
I have a program which has shown strange bugs/crashes in the past, which repeatedly also vanish again without reason.
I have identified some pieces of (pointer) logic as a potential source of these bugs. Still, the bugs can also be caused by other part of that code.
The bugs typically happen in Release builds, and not in Debug builds in case that matters.
I have taken these lines of (pointer) logic code and created a clear minimum-working example.
This minimum-working example runs without problems which I know is no conclusive proof that no undefined behavior is happening.
Therefore, I ask if someone sees if some 'C++ rules' are broken (= results in undefined behavior).
I build and develop this in Visual Studio 2019 and/or 2022.
I know this code contains very bad patterns. However, this is a minimal working example and in the actual code, many things are out of my control so I cannot simply change much of it.
For now, I just want to learn if certain pointer operations result in defined or undefined behavior.
In case one or more operation do trigger undefined behavior, I would be grateful if someone can point out which operations they are and why they trigger undefined behavior.
The code:
Main program, minimum_working_example.cpp:
#include <iostream>
#include <sstream>
#include "CppObject.h"
int main()
{
/* Create a shared pointer on the heap.
* The lifetime of this shared_ptr is managed by some managed C# code which wraps this C++ code.
* That is why the shared_ptr is created on the heap, so C# can manage the lifetime of the pointer and therefore the C++ object.
*/
std::shared_ptr<void>* regularPointerToSmartPointer = new std::shared_ptr<void>(); // Create a shared pointer on the heap, and store a regular pointer pointing to it.
// Create an CppObject and store it in the shared_ptr<void> (note that this should add a reference to the correct type deleter into the shared_ptr).
int someValue = 5; // Some value stored in the CppObject, just for illustration.
*regularPointerToSmartPointer = std::make_shared<CppObjectStuff::CppObject>(someValue); // Create an object on the heap, create a smart pointer pointing to it, and store this smart pointer on the heap at the memory reserved in the previous step.
// Just get the raw pointer to object.
void* regularPointerToObject = (*regularPointerToSmartPointer).get();
// Convert pointer to string.
std::stringstream ss1;
ss1 << std::hex << regularPointerToObject; // Pointer to hex string.
std::string regularPointerToObjectString = ss1.str();
/* Many other operations can happen here
* e.g. like passing this string to all sorts of objects which could
desire to use the instance of CppObject.
*/
// Convert string to back pointer.
std::stringstream ss2;
ss2 << regularPointerToObjectString;
intptr_t raw_ptr = 0;
ss2 >> std::hex >> raw_ptr; //Hex string to int.
void* regularPointerToObjectFromString = reinterpret_cast<void*>(raw_ptr);
// Convert the void pointer to a CppObject pointer.
CppObjectStuff::CppObject* pointerToCppObject = static_cast<CppObjectStuff::CppObject*>(regularPointerToObjectFromString);
// Do something with the CppObject behind the pointer.
int result = pointerToCppObject->GiveIntValue();
// Print result.
std::cout << "This code runs fine:" << "\n";
std::cout << result;
// Delete the shared_ptr which in turn deletes the CppObject (something the managed C# code would normally do).
delete regularPointerToSmartPointer;
}
For reference, CppObject.h:
namespace CppObjectStuff
{
class CppObject
{
public:
CppObject(int value) { _intValue = value; };
int GiveIntValue() { return _intValue; };
private:
int _intValue;
};
}
One item that could cause discussion:
I already researched specifically the following tricky case which I concluded should be allowed, see e.g. this bog post.
Note, this is similar but not fully identical to the usage in my code above so there could still be stuff I misunderstand:
// Start scope
{
// Create object in shared_ptr
std::shared_ptr<void> regularPointerToSmartPointer = std::make_shared<CppObjectStuff::CppObject>(someValue);
}
// Scope ended, shared_ptr went out of scope and should delete the `ppObjectStuff::CppObject` created before.
I am trying to print out value 123456, but it gives me the garbage value. How can I fix it? And Can you please explain why it gives the wrong value?
#include <stdio.h>
#include <stdlib.h>
struct MyInfo
{
private:
int private_key = 123456;
public:
int setkey(int value)
{
private_key = value;
}
int GetScore()
{
return private_key;
}
};
void main()
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo));
printf("%d\n", pMyInfo->GetScore());
free(pMyInfo);
}
Don't use malloc/free but rather pMyInfo = new MyInfo() and delete pMyInfo. Only new will call the constructor which initializes the value; only delete will call the destructor.
Regarding the comment, what is meant is, you can also have it on the stack, i.e. MyInfo pMyInfo;, i.e. not a pointer. That will automatically call the constructor and when it goes out of scope, the destructor.
int private_key = 123456;
This really is just a camouflaged constructor initialization which means it's the same as:
MyInfo() : private_key(123456) {}
Since malloc and friends are inherited from C and C has no classes (and thus no special member functions) whatsoever malloc and friends won't call these necessary special member functions to set up your object. The C++ equivalent new does however which is why you should always use new over malloc and delete over free.
But wait, there's more...
Actually, you shouldn't ever use new either, there are always better alternatives than using raw dynamic allocation. If you really need dynamic memory allocation then use std::unique_ptr or for multiple objects std::vector but most of the time you don't even need these ( there are tons of posts on here that explain when dynamic allocation is a must, for all the other cases just use storage with automatic lifetime) all you need in this case is a local object:
MyInfo myInfo;
printf("%d\n", myInfo.GetScore());
See how your code just got shorter, easier to maintain and cleaner to achieve the same?
When you declare a pointer of type MyInfo, it does not mean that the object it points to will actually be your struct, it just assumes it will be.
When you do malloc(sizeof(MyInfo)), you simply allocate memory of the size which your struct might take, it does not create an object. Hence, when you try to do GetScore(), it accesses memory location which it assumes contains your private_key, but instead it simply contains garbage.
Don't mix C and C++
You should avoid malloc/alloc etc in C++ and opt for new operator if you want to work with dynamically allocated objects.
Add a constructor to initialize the value
private;
int private_key;
public:
MyInfo () {
private_key = 123456;
}
And implement the main like
// without pointer
void main () {
MyInfo myinfo;
printf("%d\n", myinfo.GetScore());
}
// with pointer
void main () {
MyInfo *myinfo = new MyInfo();
printf("%d\n", myinfo->GetScore());
}
Just for reference, it is possible to initialize an object in raw storage, but it would be overkill and rather stupid for this use case. As malloc only allocate raw memory and does not construct an object, you could use a placement new to build the object in a second time:
int main() // I can't stand void main
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo)); // only allocate raw memory
new((void *) pMyInfo) MyInfo; // construct the object
std::cout << pMyInfo->GetScore() << std::endl; // no reason for C printf here
pMyInfo->~MyInfo(); // placement new requires explicit destructor call if not trivial
free(pMyInfo);
return 0;
}
DO NOT DO THAT for such a simple case. Placement new should only be used in very special cases where the allocation is not trivial, for example when you use share memory. But here the correct way is to simply use an automatic object:
int main() // I can't stand void main
{
MyInfo pMyInfo;
std::cout << pMyInfo.GetScore() << std::endl;
return 0;
}
So I've completely edited my question.
I have a map called mTextMap which contains:
typedef std::map<const std::string, Text*> TextMap;
TextMap mTextMap;
And I have the following methods:
void Foo::setUpGame()
{
Text text(1,2,3,4); //create a Text object
mTextMap["MainText"] = &text; //save it in the map!
}
Text& Foo::getText(const std::string name)
{
auto i= mTextMap.find(name);
return *(i->second); //Gets a reference to the Text that is inside the map
}
Now if I use this way:
Foo foo;
foo.setUpGame();
Text& myText = foo.getText("MainText"); // Why is this corrupted?
The object myText is completely corrupted!!
Why is this happening?
The general problem seems to be, that you think that this line:
mTextMap["MainText"] = &text;
stores the text object in the map. IT DOESN'T! It stores a pointer to the object in the map and the text object itself will - as you said yourself - automatically be destructed at the end of the function. So now your pointer points to a non-existing object, which leads to the observed errors.
There are various solutions to your problem, depending on what exactly, you try to achieve and what you are going to do with your class.
One possibility is to use a map of Text objects (instead of pointers):
typedef std::map<const std::string, Text> TextMap;
void Foo::setUpGame()
{
Text text(1, 2, 3, 4); //create a Text object
mTextMap["MainText"] = text; //copy it into the map!
}
or
void Foo::setUpGame()
{
mTextMap.emplace("MainText", Text(1, 2, 3, 4)); //Doesn't require Text to be default constructable
}
Another possibility is to create the text objects on the heap and use smart pointers (e.g. unique_ptr)
typedef std::map<const std::string, std::unique_ptr<Text>> TextMap;
void Foo::setUpGame()
{
mTextMap["MainText"] = std::make_unique<Text>(1,2,3,4); //create object on the heap an store a pointer to it in the map
}
The std::unique_ptr will automatically destroy the text object, as soon as the map gets destroyed.
If you really need to have a map of raw pointers for some reason, you can use "new" as explained by David, but don't forget to delete them when you don't use them anymore - c++ doesn't have a garbage collector (like e.g. java) that would take care of this automatically.
The "text" object is going out of scope as soon as setUpGame completes. At this point, the heap memory is freed up to be overwritten by any new use of the heap. It is essentially a temporary scratchpad of items that only exists within the scope of a function (or within explicit scope operators inside a function).
David G's advice is sound: read more about the difference between stack and heap memory, and also consider the advice to use smart pointers. However, if you want a cheap, dirty fix to your immediate problem, you can try this:
void Foo::setUpGame()
{
static Text text(1,2,3,4); // Note use of "static" keyword
mTextMap["MainText"] = &text; //save it in the map!
}
Whilst I do not advocate the use of static as a shortcut to solving more fundamental architectural memory issues, you can use this as a short-term measure if you're desperate to get things working. Labeling the object as static ensures its lifetime will outlive the scope of the function. But I would not recommend it as a long-term solution to this kind of issue.
When you dynamically allocate memory for your object, it will live as long as you do not explicitly delete it from memory, it is not deleted after you exit the method it was created in, so you can put a pointer to it in a map and it will always be there (just be sure you delete the memory when removing the object from the map).
You can test this with the following simple code, where I declare a new Int in a function, return a pointer to the memory and print it in the other function that received the map (with the pointer in it). It prints correctly, which means the memory was not freed even when out of scope.
#include <iostream>
#include <map>
std::map<std::string, int*> myMap(){
int* test = new int(1);
std::map<std::string, int*> ObjMap;
ObjMap["object"] = test;
return ObjMap;
}
int main(int argc, const char * argv[]) {
// insert code here...
std::map<std::string, int*> mmap = myMap();
std::cout << *mmap["object"] << std::endl;
return 0;
}
So to answer your question, create your object dynamically like this:
Obj* obj = new obj(1,2,3,4);
And it will not be deleted when out of scope. Still, you need to delete the memory yourself unless you use Smart Pointer, like this: delete obj; (when you remove it from the map, to free the memory as it will not be freed automatically).
PS: You should read on how the Stack and Heap works and how Dynamic and Static allocation works (using the stack OR the heap). See this c++ dynamic memory allocation tutorial to have more informations.
Like MikeMB said, using Smart Pointers is easier as you will be sure you deleted the memory, and you will also be sure you never access a deleted memory. See this Stack Overflow topic for smart pointers informations: What is a smart pointer and when should I use one?
I am wondering how one would go about returning a new object from a C++ function. For example, I have a SQLite wrapper which used to mix in Objective-C and I modifying it to be purely C++.
So, for example:
list<char*> * SqliteWrapper::RunQuery(const char *query)
{
list<char*> * result = new list<char*>();
//Process query
return result;
}
the issue that I can see in this, is that who owns the object? The calling class or the class that created the object? What is worse, is that this is very prone to memory leaks. If the caller object does not delete the newly created object, the app will end up with a memory leak.
Now that I think about this, this would make a lot of sense:
int SqliteWrapper::RunQuery(const char *query, list<char*>& result)
{
//Process query
return errorCode;
}
Are there any other approaches to this? I have been a C# programmer for a while and only now am starting to work heavily with C/C++.
Many programmers do this:
If it is a pointer that is returned, I am being given the object's identity (it's location in memory is unique) I must manage that. I am responsible for deleting it.
(Pointer = my job)
references however let you pretend you are being passed the object, to look at and use. you are not responsible for deleting these, something else is.
BUT:
"Naked pointers" may be frowned upon for code like this (it's very subjective) so some would say use a "unique_ptr" to that, these can be moved, and delete what they point to when deleted (unless the stuff is moved out of them), by returning one and not using it, it will be deleted.
(tell me if you want me to flesh this out, see also "shared_ptr" if multiple things have a pointer, this will delete what it points to when the last shared_ptr pointing to it is deleted)
Addendum 1
unique_ptr<list<char*>> SqliteWrapper::RunQuery(const char *query)
{
list<char*> * result = new list<char*>();
//Process query
return make_unique<list<char*>>(result);
}
Remember you can only move, not copy unique_ptrs
Well. You are right.
First example would be a bad style, since in such a code is hardly readable and it is hard to track bugs in it.
Usually people use the second approach with reference.
In the same way you can use pointer, allocating the return object before function call.
Third approach would be to use class instead of function. It is convinient if your function does complicated process with many parameters. In this case you store result as a data member of the class and ownership is obvious:
class SqliteWrapper {
...
class ProcessQuery {
public:
ProcessQuery():fQ(0),fP1(0){}
SetQuery(const char *query){ fQ = query; }
SetP1(int p1){ fP1 = p1; }
...
list<char*> GetResult(){ return fR; } // copy
int Run();
private:
const char *fQ;
int fP1;
...
list<char*> fR;
}
...
}
int SqliteWrapper::Process::Run()
{
//Process query
return errorCode;
}
I have
class Foo {
....
}
Is there a way for Foo to be able to separate out:
function blah() {
Foo foo; // on the stack
}
and
function blah() {
Foo foo* = new Foo(); // on the heap
}
I want Foo to be able to do different things depending on whether it's allocated on the Stack or the Heap.
Edit:
Alof of people have asked me "why do this?"
The answer:
I'm using a ref-counted GC right now. However, I want to have ability to run mark & sweep too. For this, I need to tag a set of "root" pointers -- these are the pointers on the stack. Thus, for each class, I'd like to know whether they're in the stack or in the heap.
A hacky way to do it:
struct Detect {
Detect() {
int i;
check(&i);
}
private:
void check(int *i) {
int j;
if ((i < &j) == ((void*)this < (void*)&j))
std::cout << "Stack" << std::endl;
else
std::cout << "Heap" << std::endl;
}
};
If the object was created on the stack it must live somewhere in the direction of the outer functions stack variables. The heap usually grows from the other side, so that stack and heap would meet somewhere in the middle.
(There are for sure systems where this wouldn't work)
You need to actually ask us the real question(a) :-) It may be apparent to you why you think this is necessary but it almost certainly isn't. In fact, it's almost always a bad idea. In other words, why do you think you need to do this?
I usually find it's because developers want to delete or not delete the object based on where it was allocated but that's something that should usually be left to the client of your code rather than your code itself.
Update:
Now that you've clarified your reasons in the question, I apologise, you've probably found one of the few areas in which what you're asking makes sense (running your own garbage collection processes). Ideally, you'd override all the memory allocation and de-allocation operators to keep track of what is created and removed from the heap.
However, I'm not sure it's a simple matter of intercepting the new/delete for the class since there could be situations where delete is not called and, since mark/sweep relies on a reference count, you need to be able to intercept pointer assignments for it to work correctly.
Have you thought about how you're going to handle that?
The classic example:
myobject *x = new xclass();
x = 0;
will not result in a delete call.
Also, how will you detect the fact that the pointer to one of your instances is on the stack? The interception of new and delete can let you store whether the object itself is stack or heap-based but I'm at a loss as to how you tell where the pointer is going to be assigned to, especially with code like:
myobject *x1 = new xclass(); // yes, calls new.
myobject *x2 = x; // no, it doesn't.
Perhaps you may want to look into C++'s smart pointers, which go a long way toward making manual memory management obsolete. Shared pointers on their own can still suffer from problems like circular dependencies but the judicious use of weak pointers can readily solve that.
It may be that manual garbage collection is no longer required in your scenario.
(a) This is known as the X/Y problem. Many times, people will ask a question that pre-supposes a class of solution whereas a better approach would be just to describe the problem with no preconceptions of what the best solution will be.
The answer is no, there is no standard/portable way to do this. Hacks involving overloading the new operator tend to have holes. Hacks that depend on checking pointer addresses are OS specific and heap implementation specific, and may change with future versions of the OS. You may be comfortable with that, but I wouldn't build any sort of system around this behavior.
I would start looking at different ways to accomplish your goal - perhaps you can have a totally different type to serve as the "root" in your scheme, or require the users to (properly) annotate the stack allocated types as such with a special constructor.
It is possible if you compare the value of 'this' with the current value of the stack pointer. If this < sp then you have been allocated in the stack.
Try this out (using gcc in x86-64):
#include <iostream>
class A
{
public:
A()
{
int x;
asm("movq %1, %%rax;"
"cmpq %%rsp, %%rax;"
"jbe Heap;"
"movl $1,%0;"
"jmp Done;"
"Heap:"
"movl $0,%0;"
"Done:"
: "=r" (x)
: "r" (this)
);
std::cout << ( x ? " Stack " : " Heap " ) << std::endl;
}
};
class B
{
private:
A a;
};
int main()
{
A a;
A *b = new A;
A c;
B x;
B *y = new B;
return 0;
}
It should output:
Stack
Heap
Stack
Stack
Heap
A more direct, and less intrusive method would be to look up the pointer in the memory region maps (such as /proc/<pid>/maps). Each thread has a region allocated to its stack. Static and global variables will live in the .bss section, constants in a rodata or const segment, and so on.
I am not positive what you are asking, but overriding the new operator may be what you are trying to do. As the only safe way to create an object on the heap in C++ is to use the new operator, you can differentiate between objects that exist on the heap versus other forms of memory. Google "overloading new in c++" for more information.
You should, however, consider if differentiating between the two types of memory is really necessary from inside the class. Having an object behave differently depending upon where it is stored sounds like a recipe for disaster if you are not careful!
As mentioned above, you need to control how your object is allocated through overloaded new operator. Watch out for two things however, first the 'placement new' operator that initializes your object inside the memory buffer preallocated by user; second, nothing stops the user from simply casting arbitrary memory buffer into your object type:
char buf[0xff]; (Foo*)buf;
Another way is the fact that most runtimes use a bit more memory than asked when doing heap allocations. They usually place some service structure there to identify proper deallocations by pointer. You could inspect your runtime implementation for these patterns, although it will make your code really unportable, dangerous and unsupportable overkill.
Again, as mentioned above, you really are asking for solution details ("how") when you should ask about the initial problem you devised this solution for ("why").
Nope, it can't be done reliably or sensibly.
You may be able to detect when an object is allocated with new by overloading new.
But then what if the object is constructed as a class member, and the owning class is allocated on the heap?
Here's a third code example to add to the two you've got:
class blah {
Foo foo; // on the stack? Heap? Depends on where the 'blah' is allocated.
};
What about static/global objects? How would you tell them apart from stack/heap ones?
You could look at the address of the object, and use that to determine if it is within the range that defines the stack. But the stack may be resized at runtime.
So really, the best answer is that "there's a reason why mark & sweep GC's aren't used with C++".
If you want a proper garbage collector, use a different language, one which supports it.
On the other hand, most experienced C++ programmers find that the need for a garbage collector pretty much vanishes when you learn the necessary techniques for resource management (RAII).
The meta question as asked by pax is asked "why would you want to do that" you'll likely get a more informative answer.
Now assuming you're doing this for "a good reason" (perhaps just curiousity) can get this behaviour by overriding operators new and delete, but don't forget to override all 12 variants including:
new, delete, new no throw, delete no throw, new array, delete array, new array no throw, delete array no throw, placement new, placement delete, placement new array, placement delete array.
One thing you can do is put this in a base class and derive from it.
This is kind of a pain, so what different behavior did you want?
A way for MFC classes:
.H
class CTestNEW : public CObject
{
public:
bool m_bHasToBeDeleted;
__declspec(thread) static void* m_lastAllocated;
public:
#ifdef _DEBUG
static void* operator new(size_t size, LPCSTR file, int line) { return internalNew(size, file, line); }
static void operator delete(void* pData, LPCSTR file, int line) { internalDelete(pData, file, line); }
#else
static void* operator new(size_t size) { return internalNew(size); }
static void operator delete(void* pData) { internalDelete(pData); }
#endif
public:
CTestNEW();
public:
#ifdef _DEBUG
static void* internalNew(size_t size, LPCSTR file, int line)
{
CTestNEW* ret = (CTestNEW*)::operator new(size, file, line);
m_lastAllocated = ret;
return ret;
}
static void internalDelete(void* pData, LPCSTR file, int line)
{
::operator delete(pData, file, line);
}
#else
static void* internalNew(size_t size)
{
CTestNEW* ret = (CTestNEW*)::operator new(size);
return ret;
}
static void internalDelete(void* pData)
{
::operator delete(pData);
}
#endif
};
.CPP
#include "stdafx.h"
.
.
.
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
void* CTestNEW::m_lastAllocated = NULL;
CTestNEW::CTestNEW()
{
m_bHasToBeDeleted = (this == m_lastAllocated);
m_lastAllocated = NULL;
}
Overload new() for your class. This way you'll be able to tell between heap and stack allocation, but not between stack and static/global.
I would recommend using smart pointers instead. By design, the class should have data and information about class. Book-keeping tasks should be delegated outside the class.
overloading new and delete can lead to more holes than you can imagine.
To answer your question, a reliable way (assuming your aplication isn't using more thant one thread), assuming that everithing wich is not contained by your smart pointer isn't on the heap :
-> Overloading new, so that you ca store a list of all blocs allocated, with the size of each block.
-> When the constructor of your smart pointer, search in wich block your this pointer belong. If it isn't in any block, you can say it's "on the stack" (actualy, it means it's not managed by you). Otherwise, you know where and when your pointer was allocated (if you wan't to look for orphan pointers and lasily free memory, or things like that..)
It do not depend from the architechture.
There is a solution, but it forces inheritance. See Meyers, "More Effective C++", Item 27.
EDIT:
Meyers' suggestion is summarized in an article written by Ron van der Wal, which Meyers himself linked to in his blog (in this post):
Tracking heap based objects
As an alternative to the global variable
approach, Meyers presents a HeapTracked class that uses a list to keep
track of the addresses of class instances allocated off the heap, then
uses this information to determine if a particular object resides on
the heap. The implementation goes like this:
class HeapTracked {
// Class-global list of allocated addresses
typedef const void *RawAddress;
static list<RawAddress> addresses;
public:
// Nested exception class
class MissingAddress {};
// Virtual destructor to allow dynamic_cast<>; pure to make
// class HeapTracked abstract.
virtual ~HeapTracked()=0;
// Overloaded operator new and delete
static void *operator new(size_t sz)
{
void *ptr=::operator new(sz);
addresses.push_front(ptr);
return ptr;
}
static void operator delete(void *ptr)
{
// Remove ‘ptr’ from ‘addresses’
list<RawAddress>::iterator it=find(addresses.begin(),
addresses.end(), ptr);
if (it !=addresses.end()) {
addresses.erase(it);
::operator delete(ptr);
} else
throw MissingAddress();
}
// Heap check for specific object
bool isOnHeap() const
{
// Use dynamic cast to get start of object block
RawAddress ptr=dynamic_cast<RawAddress>(this);
// See if it’s in ‘addresses’
return find(addresses.begin(), addresses.end(), ptr) !=
addresses.end();
}
};
// Meyers omitted first HeapTracked:: qualifier...
list<HeapTracked::RawAddress> HeapTracked::addresses;
There is more to read on the original article: Ron van der Wal comments on this suggestion, and then demonstrates other alternative heap tracking methods.
Take a look at the program here: http://alumni.cs.ucr.edu/~saha/stuff/memaddr.html. With a few casts, it ouputs:
Address of main: 0x401090
Address of afunc: 0x401204
Stack Locations:
Stack level 1: address of stack_var: 0x28ac34
Stack level 2: address of stack_var: 0x28ac14
Start of alloca()'ed array: 0x28ac20
End of alloca()'ed array: 0x28ac3f
Data Locations:
Address of data_var: 0x402000
BSS Locations:
Address of bss_var: 0x403000
Heap Locations:
Initial end of heap: 0x20050000
New end of heap: 0x20050020
Final end of heap: 0x20050010