考虑这个小程序:
#include <memory>
#include <vector>
class Holder {
std::vector<std::unique_ptr<A> > _items;
public:
void push(A *v) {
//Perform some checks and other stuff before pushing
_items.emplace_back(v);
};
void push(std::unique_ptr<A> &v) {
push(v.release());
};
};
class A {
};
class B : public A {
};
int main()
{
Holder h;
std::unique_ptr<A> a;
std::unique_ptr<B> b;
// It works but it's too verbose
h.push(a.release());
h.push(b.release());
// It works for a because it has the right type but not for b
h.push(a);
h.push(b);
}
我想知道是否有一种简单的方法可以编写h.push(b)
行,而不需要自己拥有所有权。
我不想使用*b
,因为指针必须在push
方法中失去所有权,并且我希望push
方法尽可能易于使用。
我觉得我应该删除push
重载,从Holder
类中获取unique_ptr
,并使用第一个有效的示例。
知道吗?
这是正确的签名:
void push(std::unique_ptr<A> v) {
//Perform some checks and other stuff before pushing
push(std::move(v));
}
取得unique_ptr
表示您正在取得所有权。
呼叫现场:
// It works but it's too verbose
h.push(std::move(a));
h.push(std::move(b));
这既是因为它是必需的,也是因为您希望更改所有权的代码是明确的。
注意,std::move(b)
代码将导致未定义的行为,因为A
缺少虚拟析构函数。
// It works for a because it has the right type but not for b
h.push(a);
这个代码是有毒的,会导致错误。您只是默默地更改了unique_ptr
的所有权。auto_ptr
具有此属性,并且被发现几乎不可能正确使用,因此被弃用,然后从标准中删除。
不要编写使unique_ptr
表现得像auto_ptr
的代码。
您应该移动而不是通过引用传递对象:
void push(std::unique_ptr<A> v) {
push(v.release());
};
然后:
h.push(std::move(a));
h.push(std::move(b));
但是唯一指针上的任何release
都是臭味,所以用另一种方式实现推送:
void push(A *v) {
//Perform some checks and other stuff before pushing
push(std::unique_ptr<A>(v));
};
void push(std::unique_ptr<A> v) {
_items.push_back(std::move(v));
};
并添加虚拟析构函数。
对于std::unique_ptr
,您应该始终拥有所有权,在这种情况下,您不需要担心释放和创建新指针。相反,使用std::move
函数,它是为此而设计的。您可以将推送功能更改为:
void push (std::unique_ptr<A> v) { _items.push_back(std::move(v)); }
然后你会用输入指针
h.push(std::move(a));
h.push(std::move(b));