Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

aboeing

Am I on the heap? & Virtual Functions

This topic is 5451 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I am trying to write a class to let me know if the object has been constructed on the heap. The following code works:
class HeapTest {
public:
	HeapTest() {
		printf("0x%x HeapTest alive!\n",this);
	}
	~HeapTest() {
		printf("0x%x goodbye from HeapTest!\n",this);
	}
	static void *operator new (size_t size) {
		void *memPtr=::operator new(size);
		printf("0x%x heap!\n",memPtr);
		return memPtr;
	}
	static void *operator new[] (size_t size) {
		void *memPtr=::operator new(size);
		printf("0x%x heap array!\n",memPtr);
		printf("sizeof(me):%d\n",sizeof(HeapTest));
		printf("therefore, i am creating %d of me\n",(size/sizeof(HeapTest))-1);
		printf("therefore the following are on the heap:\n");
		char *htp=(char *) memPtr;
		for (unsigned int i=1;i<size/sizeof(HeapTest);i++)
			printf("0x%x (%d)\n",htp+i*sizeof(HeapTest),i);
		return memPtr;
	}
	void SayHi(char *msg) {
		printf("0x%x hi:%s\n",this,msg);
	}
	int x;	

};

int main() {

	HeapTest ht;
	ht.SayHi("ht");

	HeapTest *htp = new HeapTest;
	htp->SayHi("htp");
	delete htp;

	HeapTest *htpa = new HeapTest[3];
	htpa[2].SayHi("htpa[2]");

	delete [] htpa;
	printf("eop\n");
}
Now the thing is, I wanted to use this as a base class so that I could let my memory manager correctly delete things. But when I add virtual functions everything goes wrong. Any solutions? Thanks.

Share this post


Link to post
Share on other sites
Advertisement
Heres the program output btw:

0x12ff70 HeapTest alive!
0x12ff70 hi:ht
0x431b70 heap!
0x431b70 HeapTest alive!
0x431b70 hi:htp
0x431b70 goodbye from HeapTest!
0x431b60 heap array!
sizeof(me):4
therefore, i am creating 3 of me
therefore the following are on the heap:
0x431b64 (1)
0x431b68 (2)
0x431b6c (3)
0x431b64 HeapTest alive!
0x431b68 HeapTest alive!
0x431b6c HeapTest alive!
0x431b6c hi:htpa[2]
0x431b6c goodbye from HeapTest!
0x431b68 goodbye from HeapTest!
0x431b64 goodbye from HeapTest!
eop
0x12ff70 goodbye from HeapTest!

Share this post


Link to post
Share on other sites
quote:
Hi, I am trying to write a class to let me know if the object has been constructed on the heap.

Then make the constructor private and construct objects through a factory that returns objects that have been newed into existance.

Share this post


Link to post
Share on other sites
Hi,
Sorry, I should have mentioned that I didnt want to do that. I still want to be able to create variables on the stack, but I want to know if it is deleteable.
Private constructors&destructors is too restrictive.
Thanks,
-Adrian

Share this post


Link to post
Share on other sites
Hi, I am trying to write a class to let me know if the object has been constructed on the heap.

There exist no foolproof method to do this.
See Scott Meyers, More Effective C++, Item #27 for a discussion.

Note - your base class destructor must be virtual.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]


[edited by - Fruny on October 13, 2003 10:28:28 PM]

Share this post


Link to post
Share on other sites
There exist no foolproof method to do this.

Well I think I''ve figured it out. Other than not working for multiple threads, but thats nothing that a semaphore cant solve.

Let me know if you can spot any issues with this:


static int nHeap; //this will let me know if I am on the heap


class HeapTest {
public:
HeapTest() {
printf("0x%x HeapTest alive.\n",this);
if (nHeap>0)
printf("0x%x And I am on the Heap!\n",this);
nHeap--;
}
virtual ~HeapTest() {
printf("0x%x goodbye from HeapTest.\n",this);
}
static void *operator new (size_t size) {
void *memPtr=::operator new(size);
nHeap=1;
return memPtr;
}
static void *operator new[] (size_t size) {
void *memPtr=::operator new(size);
nHeap=(size/sizeof(HeapTest))-1;
return memPtr;
}
virtual void SayHi(char *msg) {
printf("0x%x hi:%s\n",this,msg);
}
int x;
};


Output from a test program:

0x12ff6c HeapTest alive.
0x12ff6c hi:ht
0x431b60 HeapTest alive.
0x431b60 And I am on the Heap!
0x431b60 helo from ifht
0x431b60 IFHT:htp
0x431b60 goodbye from InheritFromHeapTest.
0x431b60 goodbye from HeapTest.
0x431b54 HeapTest alive.
0x431b54 And I am on the Heap!
0x431b5c HeapTest alive.
0x431b5c And I am on the Heap!
0x431b64 HeapTest alive.
0x431b64 hi:htpa[2]
0x12ff58 HeapTest alive.
0x12ff58 hi:stackht:I am on the stack
0x431b64 goodbye from HeapTest.
0x431b5c goodbye from HeapTest.
0x431b54 goodbye from HeapTest.
eop
0x12ff58 goodbye from HeapTest.
0x12ff6c goodbye from HeapTest.

Seems to work just fine...

See Scott Meyers, More Effective C++, Item #27 for a discussion.
Dont have the book, a friend told me he used static vector of addresses. But then he wouldnt be able to support the new[] operator..(?) Plus his solution would have more overhead..

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Well for a start, a very common feature of memory management is to allocate memory without constructing an object on it, and your class would fail completely under these circumstances


my_class* pmy_memory_pool = my_class.operator new(100*sizeof(my_class));


Your code now expects one object to be constructed on the heap
however i could use placement new to construct 100 objects
on the heap, 99 of which would be thought to be on the stack by your code. Also after allocating this memory i could create the next object on the stack, and not create anything on the free-store..

my_class instance_of_my_class_on_the_stack; //o_0

Your code is expecting the constructor for a heap based object, but its getting one on the stack, now when you try to delete the memory occupied by instance_of_my_class_on_the_stack, you will get your undefined behaviour. The same problem exists with operator []. It all comes from the fact that a call to operator new doesnt mean that a constructor will be called after it, but your code relies on just this, and so wont work under anything but the simplest of circumstances

Share this post


Link to post
Share on other sites
Hey thanks heaps (haha!) for the feedback, I hadn''t thought of that at all!
**SNIP** Infact, I just realised that my code wasn''t working at all. If you call operator new [] with an inherited class, it will have a different class size, **SNIP**

*time passes*
Actually, I have now got, what I believe to be a fully working solution:

#include <vector>
using namespace std;

class HeapTest {
public:
HeapTest() {
printf("0x%x HeapTest alive.\n",this);
int i;
for (i=0;i<low_address.size();i++)
if (this>=low_address[i]) {
//printf("0x%x is greater than 0x%x\n",this,low_address[i]);

if (this<high_address[i]) {
printf("0x%x I am on the heap!\n",this);
}
}

}
virtual ~HeapTest() {
printf("0x%x goodbye from HeapTest.\n",this);
}
static void *operator new (size_t size) {
void *memPtr=::operator new(size);

low_address.push_back(memPtr);

char *bytePtr = (char *)memPtr;
bytePtr+=size;
high_address.push_back((void *)bytePtr);

return memPtr;
}
static void *operator new[] (size_t size) {
void *memPtr=::operator new(size);

low_address.push_back(memPtr);

char *bytePtr = (char *)memPtr;
bytePtr+=size;
high_address.push_back((void *)bytePtr);

return memPtr;
}
virtual void SayHi(char *msg) {
printf("0x%x hi:%s\n",this,msg);
}
int x;
static vector <void *> low_address;
static vector <void *> high_address;
};

vector <void *> HeapTest::low_address;
vector <void *> HeapTest::high_address;


By using TWO vectors to store the high and low addresses of the memory we have allocated then we can determine if we are on the heap by searching through the vectors and ensureing we are inbetween the two addresses.

I dont think there are any flaws in this? Now my solution is slower than Scott Meyers

Again I would love to get feedback on this design.

Share this post


Link to post
Share on other sites
Hmm....

Would it help if you make HeapTest a templated class? If you made it HeapTest<class T> (perhaps inherited from a BaseHeapTest so that you can still aggregate them all), and then used it as 'class DerivedClass : public HeapTest<DerivedClass>,' you'd be able to cast 'this' to type T* (and thus get the correct base address of the object).



Superpig
- saving pigs from untimely fates, and when he's not doing that, runs The Binary Refinery.
Enginuity1 | Enginuity2 | Enginuity3 | Enginuity4
ry. .ibu cy. .abu ry. dy. "sy. .ubu py. .ebu ry. py. .ibu gy." fy. .ibu ny. .ebu

[edited by - Superpig on October 14, 2003 1:35:35 PM]

[edited by - Superpig on October 14, 2003 1:36:04 PM]

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!