Friendly API with uniqueptr

I use a simple graphical interface for OpenGL, mainly as an exercise for myself. The idea is to have a Gui class, where each instance can be assigned for a different rendering purpose (e.g., a back buffer or texture). GUI elements (widgets) are assigned to exactly one instance of the Gui class. I believe that storing elements inside the GUI is a typical use case for unique_ptr . Here is what I came up with:

class Element { public: Element(); virtual ~Element(); static std::unique_ptr<Element> create_unique(); }; class Gui { public: typedef std::unique_ptr<Element> element_ptr; Gui(); void addElement( element_ptr element ); void addElementRaw( Element* element ); private: std::list<element_ptr> elements; }; int main(void) { Gui gui; gui.addElementRaw( new Element() ); // 1 gui.addElement( Element::create_unique() ); // 2 gui.addElement( std::unique_ptr<Element>(new Element()) ); // 3 auto el = Element::create_unique(); gui.addElement( std::move(el) ); // 4 } 

I do not want the potential GUI user to worry about moving the pointer. However, I want to clarify the API that the GUI class takes responsibility for the Element.

  • Passing a raw pointer: simple use, but the API does not make it clear that ownership has been transferred.
  • factory Function: Simple to use, but the function must be reimplemented for each class derived from Element.
  • Manually creating unique_ptr: cumbersome for the user
  • Move semantics: seems too bulky.

I am not happy with the solution (s). I want simplicity (1), explaining to the API that gui now owns this element.

+7
c ++ c ++ 11 smart-pointers
source share
1 answer

How to simply provide arguments for a new item?

 template< typename... T > void addElement( T&&... t ) { elements.emplace_back( std::unique_ptr< Element >( new Element( std::forward< T >( t )... ) ) ); } 

With C ++ 14, you can also use std::make_unique :

 template< typename... T > void addElement( T&&... t ) { elements.emplace_back( std::make_unique< Element >( std::forward< T >( t )... ) ); } 

If you want to create elements derived from Element , you can also do this (C ++ version 14):

 template< typename C, typename... T > void emplace_back( T&&... t ) { elements.emplace_back( std::make_unique< C >( std::forward< T >( t )... ) ); } 

and it can be used as follows:

 gui.emplace_back< Element >(); // insert a class derived from Element (hope you have a virtual dtor!) gui.emplace_back< DerivedFromElement >(); // calls Element::Element( int, const char* ) or similar... gui.emplace_back< Element >( 42, "Hallo" ); 
+8
source share

All Articles