用户友好的API与unique_ptr

时间:2014-01-04 17:59:47

标签: c++ c++11 smart-pointers

我正在为OpenGL实现一个简单的GUI,主要是作为我自己的练习。我们的想法是拥有一个Gui类,其中每个实例都可以分配给不同的渲染目标(例如后缓冲区或纹理)。 GUI元素(小部件)仅分配给Gui类的一个实例。我想在GUI中存储元素是unique_ptr的典型用例。以下是我提出的建议:

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
}

我不希望GUI的潜在用户担心移动指针。但是,我想从API中明确说明GUI类取得了Element的所有权。

  1. 传递原始指针:使用简单,但API并不清楚所有权是否已通过。
  2. 工厂功能:使用简单,但需要为从Element派生的每个类重新实现该功能。
  3. 手动创建unique_ptr:对用户来说很麻烦
  4. 移动语义:看起来也很麻烦。
  5. 我对我的解决方案不满意。我想要的是(1)的简单性,同时从API清楚地知道gui现在拥有该元素。

1 个答案:

答案 0 :(得分:8)

如何为新元素提供参数?

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

使用C ++ 14,您还可以使用std::make_unique

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

如果你想创建从Element派生的元素,你也可以这样做(C ++ 14版本):

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

它可以像这样使用:

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" );