从我通过阅读这里查看的唯一指针弹出的大多数问题看出来,我觉得它应该提供构建器模式描述的行为。
我想要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;
}
我是否理解按值传递唯一指针的语义?
(为简洁/易读而省略了包含和命名空间)
答案 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)
对移动要小心,因为它们会使原始对象的内容无效。
我已经完成了举例说明威胁的例子:
#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() {}
};