I am implementing a simple GUI for OpenGL, mostly as an exercise for myself. The idea is to have a Gui class, where each instance can be assigned to a different render target (e.g. back buffer or texture). GUI elements (widgets) are assigned to exactly one instance of the Gui class. I suppose storing elements inside a 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 don't want a potential user of the GUI have worrying about moving the pointer around. However, I want to make it clear from the API that the GUI class takes ownership of the Element.
I am not happy with my solution(s). What I want is the simplicity of (1) while making it clear from the API that the gui now owns the element.
How about just providing the arguments for the new element?
template< typename... T >
void addElement( T&&... t )
{
elements.emplace_back( std::unique_ptr< Element >( new Element( std::forward< T >( t )... ) ) );
}
With C++14, you could also use std::make_unique
:
template< typename... T >
void addElement( T&&... t )
{
elements.emplace_back( std::make_unique< Element >( std::forward< T >( t )... ) );
}
In case you want to create elements derived from Element
, you could also do this (C++14 version):
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 like this:
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" );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With