Jump to content
  • Advertisement

Archived

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

null_pointer

A C++ Riddle

This topic is 6885 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

Guest Anonymous Poster
//Allocate some memory.
CBaseClass* p = new CDerivedClass;

Share this post


Link to post
Share on other sites
Advertisement
Nope. Still doesn't work. Thanks! (it's a stumper)

BTW, that shouldn't matter. When a object is created - that is derived from another class - there are 2 objects actually created. The first object is the base class and the second object is the derived class. (there can be more than one base class object, but not in this example) This is - theoretically, at least - what the memory looks like:

datadatadatadataCBaseClass{...}CDerivedClass{...}datadatadatadata

The thing coordinates the function calls between the base object and the derived object is called a virtual function table. It basically contains an array of pointers to all the virtual functions in both objects.

When you make a CBaseClass* point to a CDerivedClass object, you are actually only moving the pointer to another part of the complete object, just the CBaseClass part. The function table also allows you to call the overridden virtual functions in the derived class through the base class's pointer. For example, if you had the following code:


++ Begin Source ++

class CBaseClass
{
public:
virtual void DoSomething();
};

class CDerivedClass : public CBaseClass
{
public:
virtual void DoSomething();
};

++ End Source ++


and called DoSomething from a CBaseClass* to a CDerivedClass object, the function called would be CDerivedClass: oSomething() and not CBaseClass: oSomething().

When the delete operator is called, it does the same thing with the destructor (after all, it's just another type of function). Whether you have a CBaseClass* or a CDerivedClass* to a CDerivedClass object, the CDerivedClass::~CDerivedClass virtual destructor still gets called.

So it really wouldn't change anything.

Thanks for the effort though!!!

Also, if you step through the code in the destructor, even past that to the assembly code, the problem lies in the delete operator, when it tries to release the memory from the object. The error is:


++ Begin Error Text ++

Assertion Failed!

Statement:

ASSERT(pHead == pFirstBlock);

++ End Error Text ++


So it's not detecting the derived class object's memory correctly, and only when it has a virtual destructor in the DLL. Why?

[This message has been edited by null_pointer (edited November 12, 1999).]

Share this post


Link to post
Share on other sites
Tried it in VC 6.0 and it worked fine. Not only that, but the project I've been working on uses DLLs that are built just that way and I havn't had any problems with it.

Share this post


Link to post
Share on other sites
The problem must have been fixed then. Thanks for testing it!

I think it came about this way (I could be wrong on this):

Microsoft added their own "Microsoft-specific" keyword to the C++ language to keep a step ahead of the competition. But, unfortunately, the new and delete operators are part of the standard C++ run-time library and can't be changed for each compiler. So they couldn't track the memory usage across the DLL border, when virtual destructors were involved AND the dllexport storage class specifier was used to export the classes. This was fixed in the later version of the standard run-time library when the C++ standard added support for the export and import keywords. (Am I right on this?)

Thanks again.

Share this post


Link to post
Share on other sites
This is (er, was) a known problem and documented in the Microsoft Knowledge Base.

It appears they fixed it in either 5.0 or 6.0.

KB article: Q122675

------------------
-vince


Share this post


Link to post
Share on other sites
Please do not reply without trying the included source code!

I found a bug (or limitation) in C++. For reference, I use MS Visual C++ 4.0 Standard. (If this "problem" has been fixed in a later version, please let me know.)

NOTE: The __declspec(dllexport) and __declspec(dllimport) keywords were (I think) replaced with the "export" and "import" keywords in later versions of C++.

If you create a DLL containing some classes with virtual destructors, and then a program that uses those classes - using new and delete - an ASSERTion error pops up from the delete operator. To illustrate this "problem", I included some (relatively) simple source code:


++ The DLL Source Code ++

// TestDLL.cpp

#include

class __declspec(dllexport) CBaseClass
{
public:
// Just dummy methods
CBaseClass() {};
virtual ~CBaseClass() {};
};

class __declspec(dllexport) CDerivedClass
: public CBaseClass
{
public:
// Just dummy methods
CDerivedClass() {};
virtual ~CDerivedClass() {};
};

++ End DLL Source Code ++

++ Program Source Code ++

// TestProgram.cpp

#include

class __declspec(dllimport) CBaseClass
{
public:
// Just dummy methods
CBaseClass();
virtual ~CBaseClass();
};

class __declspec(dllimport) CDerivedClass
: public CBaseClass
{
public:
// Just dummy methods
CDerivedClass();
virtual ~CDerivedClass();
};

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
// Allocate some memory.
CDerivedClass* p = new CDerivedClass;

// Delete the memory.
delete p; // crashes here
p = NULL;

// Then just return.
return 0;
}

++ End Program Source Code ++


Is this just a bug in the Microsoft compiler? Or is it a problem with DLLs? Thanks for your patience - this has really bugged me!!

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!