0

recently I've been thinking about the problem of passing object through dll boundaries in c++. I found many solutions with advantages and disadvantages. I wasn't satisfied with them so I spend a while thinking about how to solve this issue. Finally I came up with this solution. What do you think about it? Does it protect against all the possible threats and encourages good design?

EDIT. By threats I mean issues listed in the Marked Answer to this question:

How do I safely pass objects, especially STL objects, to and from a DLL?

In my understanding it should bypass all the problem with compiling dll and exe with different compilers, using static cruntime, passing objects through dll boundaries. The only thing that goes through dll boundary is object pointer and function addresses, which - to the best of my knowledge - is safe. The inlined creation of shared_ptr makes sure that the layout of shared_ptr is taken from client module. Yet the code of creation and destruction is in dll.cpp so it will happen in dll module.

Of course naming functions "doNotUse" is not a perfect solution to make people... not use your functions, but I can't see how to avoid that if we insist on using C interface (c++ would enable us to use private / protected access keywords).

dll.h

#ifdef DLL_EXPORTS
#define EXPORT_OR_IMPORT __declspec(dllexport)
#else
#define EXPORT_OR_IMPORT __declspec(dllimport)
#endif
#include <memory>

class theInterface
{
public:
    virtual void print() = 0;
    virtual ~theInterface();
};

extern "C" {
    EXPORT_OR_IMPORT theInterface* doNotUseThisFunction_create(/* arguments*/);
    EXPORT_OR_IMPORT void doNotUseThisFunction_destroy(void* object);
}

inline std::shared_ptr<theInterface> getObject(/*argument*/)
{
    return std::shared_ptr<theInterface>(doNotUseThisFunction_create(/*arguments*/), doNotUseThisFunction_destroy);
}

dll.cpp

#include "dll.h"

#include <string>
class theObject : public theInterface
{
public:
    theObject();
    ~theObject() override;

    void print() override;
private:
    std::string someMemberWithMemoryAllocationOnHeap;
};

// (function definitions to make it compile)


theInterface* doNotUseThisFunction_create(/* arguments*/)
{
    return new theObject();
}

void doNotUseThisFunction_destroy(void* object)
{
    delete reinterpret_cast<theInterface*>(object);
}
Marcin K.
  • 584
  • 1
  • 5
  • 19

0 Answers0