这是对unique_ptr的正确使用吗?

时间:2016-09-15 03:45:47

标签: c++ return smart-pointers 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;
}

我是否理解按值传递唯一指针的语义?

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

2 个答案:

答案 0 :(得分:3)

std :: unique_ptr无法复制。相反,您必须移动uptr才能正确转移基础指针的所有权。

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

答案 1 :(得分:1)

  

我是否理解按值传递唯一指针的语义?

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

move

对移动要小心,因为它们会使原始对象的内容无效。

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

#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()内移动,但编译器不会向您发出有关Segfault潜力的警告。

此外,我建议您只使用T Builder<T>::Close()代替unique_ptr<T> Builder<T>::Close(),因为后者只会限制课程的灵活性。

为什么不让子类管理他们正在创建的实例。如果他们正在创建的实例无法进行变异,则子类需要存储有关该实例的信息,直到创建该实例(Close()为止)并且将不必要地携带unique_ptr<T>

以下是我改变Builder类的方法:

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