tags:

views:

905

answers:

6

if i use the new keyword in my lib which is built differently then my main app. when i delete it in my main app with delete is there a chance that i may get a crash/error?

+4  A: 

yes indeedy. In particular you see problems with debug/release heaps being different, also if your library uses placement new, or any custom heap you'll have a problem. The Debug/Release issue is by far the most common though.

Jesse Pepper
Yup this happens
Robert Gould
Can also happen when C++ libs are statically linked into a Windows DLL.
jmucchiello
+5  A: 

Yes, you will. A simple solution is to provide Create and Delete functions in your library that can be called from the main application. The Create function will perform the new and return a pointer, which is later passed into the Delete function for deletion.

Charles Anderson
+6  A: 

It depends. If you're talking about a static library, then you'll probably be OK -- the code will run in the same context as the main program, using the same C++ runtime library. This means that new and delete will use the same heap.

If you're talking about a shared library (a DLL), then you probably won't be OK. The code running in the DLL might be using a different C++ runtime library, which means that the layout of the heap will be different. The DLL might be using a different heap altogether.

Calling delete (in the main program) on a pointer allocated by the DLL (or vice versa) will lead to (at best) an immediate crash or (at worst) memory corruption that'll take a while to track down.

You've got a couple of options. The first is to use the "factory method" pattern to create and delete these objects:

Foo *CreateFoo();
void DeleteFoo(Foo *p);

These should not be implemented in the header file.

Alternatively, you can define a Destroy method on the object:

class Foo
{
    ~Foo();

public:
    virtual void Destroy();
};

...again, don't implement this in the header file. You'd implement it thus:

void Foo::Destroy()
{
    delete this;
    // don't do anything that accesses this object past this point.
}

Note that the destructor for Foo is private, so that you have to call Foo::Destroy.

Microsoft COM does something similar, where it defines a Release method that deletes the object when its reference count drops to zero.

Roger Lipscombe
+1  A: 

You're quite right that there's a problem there, but for most cases there's an even simpler solution than the other answers (so far) have proposed. You can continue using new and delete freely -- all you need to do is overload new and delete for each class in your library that might be used across DLL boundaries.

Personally, I just defined a simple class to provide the needed functionality:

class NewDelete
{
    public:
        void *operator new (size_t size);
        void operator delete (void *memory);
        void *operator new (size_t size, void *ptr);
        void operator delete (void *memory, void *ptr);
};

As long as those four member functions are all defined in the same DLL, then any class which derives from this class is automatically "DLL-safe" -- new and delete can be used normally on them without worrying about DLL boundaries.

Sol
-1.I've been looking at this same sort of idea, and have noticed that this practice is quite flawed. I can't (yet) speak for operator delete, but if operator new fails to allocate memory within the DLL space a std::bad_alloc exception is raised, since shared libraries or DLLs are not acknowledged by Standard C++ the behaviour is undefined. As a general rule exceptions will not cross shared library or DLL boundaries. Yes this happens to work if both you and your client use matching development environments, but the moment either one changes, everything will blow up in your clients' face.
Geoff
I should clarify in my above note: It happens to work with (recent) matching development environments of MSVC, don't know about any others though.
Geoff
+1  A: 

It is a problem that I have only seen on Windows.

The Unixish systems do not make a habit of forcing shared libraries to link to different versions of the same library within the same program and all loaded symbols are visible globally. That means that if an object is allocated in one part of code and deleted in another, both are using the same system library to do it.

I have to say, this problem Windows creates with its various C runtime DLLs is really annoying and unnatural to a C programmer. Look at the C library; it has functions like strdup that malloc the string and expect the programmer to call free() on it. But do the same thing in your own library on Windows and just wait for the explosion. You'll have to wait, too, because it won't happen during development but only after you've given the compiled DLL to some other poor sap.

Zan Lynx
This has nothing to do with the OS, but the way libc is linked. I worked at a Linux shop where we were actually statically linkng libc to our application, and it lead to exactly the same problem.
Nemanja Trifunovic
If you do strdup and free in your library, you are fine. It's only when you do strdup in one runtime and free in another, then there's a problem. And Zan Lynz is correct, this happens on all platforms if you want/need multiple runtimes.
Magnus Hiie
+2  A: 

Old New Thing has covered this before. He also gives a list of Microsoft's main solutions.

Max Lybbert