4

I have this pieces of code:

class DLL_API MyClassWrapper
{
private:

    MyClass * m_myClass;

public:
    MyClassWrapper(SIZE inputSize);
    ~MyClassWrapper();
     inline int OutputSize();

}
typedef  std::shared_ptr<MyClassWrapper> MyClassWrapperPtr;

extern "C"
{
     DLL_API MyClassWrapperPtr CreatreMyClassWrapper(SIZE inputSize)
     {
          return std::make_shared<MyClassWrapper>(inputSize);
      }
}

But it doesn't work, with error:

Error   1   error C2526: CreatreMyClassWrapper: C linkage function cannot return C++ class 'std::shared_ptr<_Ty>'   

I understand the problem, but how can I fix it?

The options that I can see are:

1- Don't pass a shared pointer. which means that DLL user should delete the pointer after they used it.

2- Don't use extern "C" : which means that I must use mangled names.

Is there any other solution?

mans
  • 17,104
  • 45
  • 172
  • 321
  • Maybe returning a pointer from the function and add another (inlined?) function that wraps the pointer into a shared pointer? – user1781290 Jun 02 '14 at 11:39
  • 1
    Templates should never be used in public Dll interface. Return plain pointer and add Release function to Dll which deletes it. Don't expect to have smart pointer functionality working with C client. – Alex F Jun 02 '14 at 11:39
  • @user1781290 How can I make sure that pointer is deleted inside dll? – mans Jun 02 '14 at 11:42
  • @AlexFarber: Then my user should be intelligent to delete the pointer. Is there any way to o it without asking user to delete the pointer? – mans Jun 02 '14 at 11:44
  • My suggestion is simply to have a C-style interface, returning a C-style pointer. Then add a inline C++-function that calls the C-function and returns the resulting pointer wrapped into shared_ptr – user1781290 Jun 02 '14 at 11:46
  • @user1781290 That doesn't work. The object is created inside DLL and should be deleted inside DLL too. If I create a shared_ptr then it would delete it in application memory space and not dll memory space. Am I missing something here? – mans Jun 02 '14 at 11:49
  • I'm actually not sure if this might cause a problem. If it does, you can create a smart_ptr with a custom deleter – user1781290 Jun 02 '14 at 11:52
  • @user1781290: problem explained here: http://blogs.msdn.com/b/oldnewthing/archive/2006/09/15/755966.aspx – mans Jun 02 '14 at 11:55
  • @user1781290 Do you have any sample code with custom delete? – mans Jun 02 '14 at 11:55
  • Have a look at this: http://www.cplusplus.com/reference/memory/shared_ptr/shared_ptr/ Version (4) has the custom deleter – user1781290 Jun 02 '14 at 11:56
  • 1
    Class instance should be deleted in the same Dll which created it. You may decide to track all created instances inside Dll and release them when necessary, if client didn't release them. When to do this - it depends on your program logic. But if you decided to write a wrapper for C clients, how can you pass smart pointers to such client? This is pure API interface, client may be everything from Assembly to .NET or Java. Again - client should not delete the class instance, it should call your Release function. – Alex F Jun 02 '14 at 12:07

1 Answers1

12

Straight to the point, to return C++ object from C function - just returns it via output arguments:

extern "C"
{
     DLL_API void CreatreMyClassWrapper(SIZE inputSize, SomeClass* outputPtr)
     {
          *outputPtr = SomeClass(....);
     }
}

In your example SomeClass == MyClassWrapperPtr, so:

extern "C"
{
     DLL_API void CreatreMyClassWrapper(SIZE inputSize, MyClassWrapperPtr* outputPtr)
     {
          *outputPtr = make_shared<MyClassWrapper>(inputSize);
     }
}

Consider however to change your interface a little, because in current shape you need to be sure that your applications and DLLs shall use the same compiler, linker, settings, libraries...*

You might want to export Create and Delete from your DLL to be sure memory management will occur in your DLL (this is based on this answer:

DLL

extern "C"
{
     DLL_API MyClassWrapper* CreateMyClassWrapper(SIZE inputSize)
     {
          return new MyClassWrapper(inputSize);
     }
     DLL_API void DeleteMyClassWrapper(MyClassWrapper* wrapper)
     {
          delete wrapper;
     }
}

Application

     shared_ptr<MyClassWrapper> myClassWrapper(CreateMyClassWrapper(inputSize), 
                                               DeleteMyClassWrapper);
Community
  • 1
  • 1
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112