Click here to Skip to main content
13,548,896 members
Click here to Skip to main content
Add your own
alternative version

Tagged as


32 bookmarked
Posted 22 May 2013
Licenced MIT

How to ensure proper dynamic library boundary crossing for objects using smart pointers' custom deleters

Rate this:
Please Sign up or sign in to vote.
Ensuring that objects allocated in one dynamic library are deleted by the same library has always been a challenge. Solutions prior to the advent of C++11 often make the usage of the library cumbersome. This is a solution using smart pointers' custom deleters.


Many prominent C++ experts promote a widespread usage of smart pointers to a point where they claim that in modern C++, the visible usage of the keyword new should disappear (well, at least when C++14 will be around to fix the lack of std::make_unique). All dynamic allocations should be hidden by the Standard Library, either with containers like std::vector or with smart pointers.

The standard library's smart pointers can be customized in the way they handle the de-allocation of the memory they hold. This feature is the key to make elegant boundary crossing possible as suggested by this article.


An object is said to cross a dynamic library boundary when it is instantiated within an assembly and consumed by another assembly. A common way this happen is when a factory-like structure instantiate objects and return pointers to them in a dynamic link library.

For example, lets say another library or an executable that links with this library uses the factory to dynamically instantiate and retrieve a pointer to an object. The assembly that consumes the pointer can do anything with it, including a delete on the pointer to free the memory it points to. If the library that allocates the memory and the assembly that consumes the pointer use different versions of the dynamic memory allocation OS run-time library (called the CRT on Windows), there is going to be a problem in the memory allocation book-keeping. For a Microsoft specific example of the problem, see this.

Typically, before the advent of C++11, library developers had to provide functions for de-allocation of objects that were allocated within their library's boundaries, in order to avoid this problem. This had the undesirable side effect that interfaces of such libraries were heavier and required a per-library specific know-how to correctly allocate and de-allocate objects of the library.

An ideal case would be an allocation/de-allocation scheme that the user don't need to know about. He/she just calls the allocation mechanism of the library (e.g. a factory) and don't even bother about de-allocation.

Using the code

The code attached to this article is divided in two projects. It has been done and packaged as a Visual Studio 2012 solution, but it would compile and run fine on g++. You can use Visual Studio Express 2012, freely available from Microsoft. The first project is ExecutableConsumer, which a simple main file that uses a library's factory to instantiate objects from the library. The second project is LibraryFactory, which illustrates a problematic situation and the solution.  

The problematic situation is a singleton factory (called ProblematicFactory) that instantiates an object and returns a raw pointer to it. The solution is another singleton factory (called SafeFactory) that instantiates an object and returns a std::unique_ptr to it, having its custom deleter properly set so that the de-allocation is done in the DLL.

If you run the program in debug mode in Visual Studio, with the macro USE_PROBLEMATIC_FACTORY_AND_CAUSE_HEAP_CORRUPTION defined, you will be able to see that the debugger detects a heap corruption.

Note that the projects provided in the solution are willingly linking with different version of the CRT in order to illustrate the heap corruption problem.

Since code is worth a thousand words, the following sections will be mainly code containing didactic comments from the attached file.

The executable's main file

Note that contexts are created in the main (by using curly braces) to encapsulate individual examples. Remember that at the exit of a context, all local variables are destroyed.

#include <ProblematicFactory.h>
#include <SafeFactory.h>

// change this undef to a define to see the heap corruption assert in debug
int main()
    // this allocation is done the the DLL
    auto wMyObject = ProblematicFactory::getInstance().create();
    // this deallocation is done in the current assembly
    delete wMyObject;
    // when the DLL and this assembly are linked with the exact same CRT DLL,
    // the delete will work properly, otherwise, it will cause heap corruption.
    // always use auto when possible!
    auto wMyObject = SafeFactory::getInstance().create();
    // When the program will hit the following curly brace,
    // wMyObect will be automatically deleted
    // using the custom deleter provided in MyClass.h.
    // No need to send it back to a de-allocation
    // function of the library!
    // std::unique_ptr can be automatically promoted to a std::shared_ptr
    // and the custom deleter follows, feels like magic!
    std::shared_ptr< MyClass > wMyObject = SafeFactory::getInstance().create();
    // Same behavior as the example above,
    // since the shared count will reach zero on the following
    // curly brace.
  return 0;

The library's problematic factory

This is a typical implementation of a factory that returns a raw pointer to objects it can create.

#pragma once
#include "DllSwitch.h"
#include "MyClass.h"

class LIBRARYFACTORY_API ProblematicFactory
  static ProblematicFactory & getInstance();
  MyClass * create() const;

The library's safe factory

Syntactically, using this factory is essentially the same as using the problematic one (see in the main file), but it encapsulate the raw pointer in a std::unique_ptr.

#pragma once
#include "DllSwitch.h"
#include "MyClass.h"

#include <memory>

  static SafeFactory & getInstance();
  // Note that this function will not be not part of the DLL, so no std::unique_ptr
  // crosses a library boundary! It is going to be built in the client's translation
  // units, therefore it uses the std::unique_ptr of the client. Also note that there
  // is no need to explicitely provide a custom deleter, since a specialization of
  // std::default_delete exists for the class MyClass (see MyClass.h).
  inline std::unique_ptr< MyClass > create() const
    return std::unique_ptr< MyClass >(doCreate());
  MyClass * doCreate() const;

The library's object that crosses boundaries

Note that the default_delete class in this file is a specialization of a std class, so it needs to be in the std namespace.

#pragma once
#include "DllSwitch.h"

#include <memory>

namespace std
// The following is a specialization of default_delete used by unique_ptr
// for the class MyClass. You need this for all types that the factory can create.
class LIBRARYFACTORY_API default_delete< MyClass >
  void operator()(MyClass *iToDelete);

Points of Interest

Having code in your projects in the std namespace can seem strange at first, but this is a specialization for your classes. For some std templates, this is totally legal and std::default_delete is a perfect candidate for specialization. Consult this post addressing the question if you are interested.

Following a comment below, I have added MyClassPluginBuilder in the library, so that it is possible to instantiate MyClass from an executable that would have open the library at runtime like a plugin.


  • v1.0 - 2013-05-20: Initial release.
  • v1.1 - 2014-08-26: Added MyClassPluginBuilder and ExecutableConsumerPlugin


This article, along with any associated source code and files, is licensed under The MIT License


About the Authors

Philippe Cayouette
Software Developer (Senior) CAE Inc.
Canada Canada
No Biography provided

Sebastien Gibeau
Software Developer (Senior)
Canada Canada
No Biography provided

You may also be interested in...


Comments and Discussions

QuestionOnly for different runtime libs? Pin
_kb_27-Aug-14 7:46
member_kb_27-Aug-14 7:46 
AnswerRe: Only for different runtime libs? Pin
Philippe Cayouette1-Sep-14 17:46
memberPhilippe Cayouette1-Sep-14 17:46 
GeneralMy vote of 5 Pin
koothkeeper27-Aug-14 3:17
professionalkoothkeeper27-Aug-14 3:17 
QuestionWill this work with plugins? Pin
Member 1093767110-Jul-14 2:49
memberMember 1093767110-Jul-14 2:49 
AnswerRe: Will this work with plugins? Pin
Philippe Cayouette26-Aug-14 5:03
memberPhilippe Cayouette26-Aug-14 5:03 
QuestionWorth price of admission... Pin
Aescleal5-Dec-13 23:42
memberAescleal5-Dec-13 23:42 
AnswerRe: Worth price of admission... Pin
Philippe Cayouette6-Dec-13 14:15
memberPhilippe Cayouette6-Dec-13 14:15 
GeneralRe: Worth price of admission... Pin
Aescleal8-Dec-13 22:31
memberAescleal8-Dec-13 22:31 
QuestionSource code not available Pin
Stone Free24-May-13 4:15
memberStone Free24-May-13 4:15 
AnswerRe: Source code not available Pin
Philippe Cayouette24-May-13 6:27
memberPhilippe Cayouette24-May-13 6:27 
GeneralRe: Source code not available Pin
peterchen29-May-13 5:42
memberpeterchen29-May-13 5:42 
GeneralRe: Source code not available Pin
Philippe Cayouette29-May-13 7:03
memberPhilippe Cayouette29-May-13 7:03 
GeneralRe: Source code not available Pin
peterchen29-May-13 22:07
memberpeterchen29-May-13 22:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.180515.1 | Last Updated 26 Aug 2014
Article Copyright 2013 by Philippe Cayouette, Sebastien Gibeau
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid