Question

Rolling my own GUI library for a side-project. Refactoring to use smart pointers; however, I ran into an issue.

I'm aware that you do not want to to use smart pointers across DLL boundaries for obvious reasons. But I feel dirty using 'new' in application code. See below:

// MYFINANCEAPP.H
class MyFinanceApp : public Application
{

MyFinanceApp() : mMainWindow(make_unique<Window>)
{
  mMainWindow->AddControl(new Button("testButton"));
}

private:
  std::unique_ptr<Window> mMainWindow;
};

// WINDOW.H
class Window
{
public:
  void AddControl(const Control& control)  //QUESTION: HOW DO I GET SMART POINTER HERE???
  {
    mControls.emplace_back(control)
  }
private:
  std::vector<std::unique_ptr<Control>> mControls;  //Want to use smart pointers so I am not responsible for managing...

};

Am I better to use C++98 style and semantics and handle it myself. Obviously I do not want to pass smart pointers across the interface boundary (i.e. AddControl), but I don't want to be responsible for handling the lifetime of the controls.

Additionally, I feel really dirty using "new Button("testButton")).

Was it helpful?

Solution

Actually, yes, you want to use smart-pointers across DLL boundaries.

Doing so can, depending on the smart-pointer (Think std::shared_ptr<T> here) allow you to make sure the same entity doling out a resource will also reclaim it in the appropriate manner.

Of course, std::unique_ptr<T, D>s is used for that too, but not across DLL-boundaries as it is usually does not carry the originating DLL's context, std::default_delete<T> is stateless.

As an aside, there's std::make_unique<T>() since C++14.

OTHER TIPS

Different problems are addressed here:

  • First, a unique_ptr is unique and can't be copied. So passing the smart pointer by value is not possible. Same for, as you seem to intend to do, passing it by reference and copying it into a vector is not possible. Use a unique pointer only for objects that are known only by their owner.
  • If you want to use a smart pointer as a pointer or as a handle, with several copies of it, you should use shared_ptr. You can copy it as you want, and if the use count decreases to zero, the memory is freed as for unique_ptr.
  • Passing memory allocated pointer across DLL boundaries is delicate, because you might use different libraries on both sides, which might cause inconsistencies.

To come back to the DLL boundaries, template code is instantiated in the client part of your library. Different version than used on your DLL side might cause the above mentioned inconsistencies, with non matching allocation and releasing. If you always use the same version on both sides, and only use dynamic linking (no code nor library using static linking), it could as well work perfectly. But of course you can't assume such a favorable condition if you package your library for use by third parties.

Unfortunately, there's no easy solution. Especially if you hope to free automatically based on use count of what happens on the client side. An interesting alternative would be to use a pimpl approach:

  • only library allocates and frees GUI objects with or without smar pointers
  • you wrap this pointer into template (e.g. header only, instantiated on the client side) with your own use-counting logic, and call your library functions to kill unused objects.
Licensed under: CC-BY-SA with attribution
scroll top