2016-09-15 175 views
2

从我通过阅读大部分在这里查询时发现的问题来看,在查找唯一指针时弹出,我认为它应该提供Builder模式描述的行为。这是unique_ptr的正确用法吗?

我希望Builder的任何实例(或其子类,因为它没有实现任何修改正在构建的对象的过程)拥有正在构建的对象,直到Close返回指向调用者的唯一指针,指出来电者拥有所有权。

Builder.h

template <class type> class Builder 
{ 
public: 
    ~Builder(); 
    unique_ptr<type> Close(); 
protected: 
    Builder(); 
    unique_ptr<type> _uptr; 
}; 

Builder.cpp

template<class type> Builder<type>::Builder() 
{ 
    uptr = make_unique<type>(); 
} 

template<class type> Builder<type>::~Builder() 
{} 

template<class type> unique_ptr<type> Builder<type>::Close() 
{ 
    return uptr; 
} 

我是否懂得按值传递的唯一指针的语义?

(包括和为了简洁省略/易读性命名空间)

回答

3

的std ::的unique_ptr不能被复制。相反,为了正确传输基础指针的所有权,您必须向上移动uptr。

template<class type> unique_ptr<type> Builder<type>::Close() 
{ 
    return std::move(uptr); 
} 
+0

谢谢!这就说得通了。我有一个暗示,我没有适当地转移。 – ophilbinbriscoe

1

我是否懂得按值传递的唯一指针的语义?

您可以move从的unique_ptr:std::move(this->_uptr)

要与移动慎之又慎无效原始对象的内容。

我已经完成了你的例子来举例说明威胁:

#include <iostream> 
#include <memory> 

template<typename T> class Builder 
{ 
public: 
    virtual ~Builder() {} 
    std::unique_ptr<T> Close(); 
protected: 
    Builder() {} 
    std::unique_ptr<T> _uptr; 
}; 

class IntBuilder: public Builder<int> 
{ 
public: 
    IntBuilder() : Builder<int>() { 
     this->_uptr = std::unique_ptr<int>(new int); 
    } 
    void setValue(int x) { 
     *(this->_uptr) = x; 
    } 
    std::unique_ptr<int> Close() { 
     return std::move(this->_uptr); 
    } 
}; 

int main() { 
    IntBuilder b; 
    b.setValue(3); 
    auto i = b.Close(); 
    std::cout << *i << std::endl; // OK 
    auto i2 = b.Close(); 
    std::cout << *i2 << std::endl; // Segmentation fault 
} 

虽然this->_uptr是内IntBuilder::Close()移动时,编译器不会警告你的段错误的潜力。


而且我只是用T Builder<T>::Close()代替unique_ptr<T> Builder<T>::Close()作为类的,后者只是限制灵活性建议。

此外,为什么没有子类管理他们创建的实例。如果他们创建的实例不能被改变,那么子类需要存储关于实例的信息,直到其创建(在Close()),并且将不必要地携带unique_ptr<T>

以下是我想改变生成器类:

template<typename T> class Builder 
{ 
public: 
    virtual ~Builder() {} 
    T&& Close(); 
protected: 
    Builder() {} 
}; 
+0

我完全意识到我原来的定义是刚性的。其中一部分原因是因为这最终会成为课程的更大交付成果的一部分,其分级标准完全侧重于我们通过C++理解和使用设计模式。 – ophilbinbriscoe

+0

我也在一个团队中工作,我们所有人都是新来的语言,所以对于我们更原始的用户定义类型有严格的使用模式,似乎可以消除我的同伴的不明确性。 虽然我看到了这样做背后的动机。 阅读此: http://stackoverflow.com/questions/5481539/what-does-t-double-ampersand-mean-in-c11 – ophilbinbriscoe

+0

我仍然有点模糊了究竟什么时候关闭返回。如果构建器实例是MyClassBuilder,则返回一个包含许多成员的对象实例,其中一些值,其中一些指针,所有权会发生什么变化?不要通过移动内部来避免复制?或者它是否复制,因为T的实例不是临时的? – ophilbinbriscoe