2016-02-24 2 views
0

У меня есть класс Widget, который должен иметь уникальное право собственности на другой виджет. Я хочу реализовать функцию, которая передает этот виджет другому виджету. Я узнал, что лучший способ реализовать концепцию единого владения std::unique_ptr, однако я не могу заставить его работатьПередача std :: unique_ptr между Widgets

Это код:

class Widget 
{ 
public: 
    Widget(void) { } 
    virtual ~Widget(void) { /* */ } 
    void successor(Widget&& successor) 
    { 
     this->_successor = std::unique_ptr<Widget>(&successor); 
    } 
    void refer_value(int a) 
    { 
     _successor->value = a; 
    } 
    auto refer_value(void) const -> int 
    { 
     return _successor->value; 
    } 
    auto get(void) -> Widget& 
    { 
     return *_successor; 
    } 

    int value; 
private: 
    std::unique_ptr<Widget> _successor; 
}; 

Он компилирует без проблем, но когда я попробуйте запустить это:

int main(void) 
{ 
    Widget a{}; 
    Widget b{}; 
    Widget c{}; 

    a.successor(Widget{}); 
    a.refer_value(5); 

    b.successor(std::move(a.get())); 
    std::cout << b.refer_value(); 
} 

Я получаю ошибку сегментации. В чем проблема?

И дополнительно, как бы мне пришлось написать реализацию функции successor(), если бы я хотел передать Widget c. Я мог бы запустить его только для rvalues.

ответ

3

Здесь

this->_successor = std::unique_ptr<Widget>(&successor); 

Вы создаете unique_ptr на объект, который будет уничтожен после выхода из области видимости.

Кроме того, здесь

b.successor(std::move(a.get())); 

Вы принимаете адрес существующего указателя в unique_ptr, и назначение его еще одинunique_ptr. В основном это неправильное/двойное освобождение от места по всему месту.

Я высоко не знаю, что вы пытаетесь сделать здесь. Во всяком случае, если я могу просто ограничить себя к числу изменений, имеющих отношение к управлению памятью здесь для того, чтобы иметь этот код имеет смысл:

class Widget 
{ 
public: 
    Widget(void) { } 

    virtual ~Widget(void) { /* */ } 

    void successor(std::shared_ptr<Widget> successor) 
    { 
     this->_successor = std::move(successor); 
    } 

    void refer_value(int a) 
    { 
     _successor->value = a; 
    } 

    auto refer_value(void) const -> int 
    { 
     return _successor->value; 
    } 

    std::shared_ptr<Widget> get() 
    { 
     return _successor; 
    } 

    int value; 

private: 
    std::shared_ptr<Widget> _successor; 
}; 

int main(void) 
{ 
    Widget a{}; 
    Widget b{}; 
    Widget c{}; 

    a.successor(std::make_shared<Widget>()); 
    a.refer_value(5); 

    b.successor(a.get()); 
    std::cout << b.refer_value(); 
} 
+0

Я хочу, чтобы гарантировать, что точки нет двух виджетов в одном виджете. Однако, когда я вызываю 'std :: cout << a.refer_value();' в вашем коде, я также получаю 5. – hgiesel

+0

@henrikgiesel Вы можете сделать ':: get()' return 'std :: shared_ptr &', а затем 'move()' it в 'b.successor()'. Однако тогда 'a.refer_value()' будет разыменовывать нулевой указатель, поэтому вам нужно следить за этим. –

+0

Думаю, я мог бы обойти это, называя указатель 'operator bool' на указателе. Однако мне все равно понравится решение для 'std :: unique_ptr' – hgiesel