C++ 带继承的模板参数推断

C++ 带继承的模板参数推断,c++,templates,C++,Templates,考虑到这个小项目: #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

考虑到这个小项目:

#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);
}
#包括
#包括
阶级持有者{
标准::向量_项;
公众:
无效推力(A*v){
//推前进行一些检查和其他工作
_项目。安置后(v);
};
无效推送(标准::唯一\u ptr&v){
推动(v.释放());
};
};
甲级{
};
B类:公共A{
};
int main()
{
持有人h;
std::唯一的ptr a;
std::唯一的ptr b;
//它是有效的,但太冗长了
h、 推动(a.释放());
h、 推动(b.释放());
//它适用于a,因为它具有正确的类型,但不适用于b
h、 推(a);
h、 推(b);
}
我想知道是否有一种简单的方法来编写
h.push(b)
行,而不必为自己提供所有权

我不想使用
*b
,因为指针必须在
push
方法中失去所有权,我希望
push
方法尽可能容易使用

我觉得我应该从
Holder
类中移除
push
重载,并使用第一个有效的示例


有什么想法吗

您应该移动,而不是通过引用传递对象:

void push(std::unique_ptr<A> v) {
    push(v.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));
};
无效推送(A*v){
//推前进行一些检查和其他工作
推送(std::unique_ptr(v));
};
无效推送(标准::唯一\u ptr v){
_项目。推回(标准::移动(v));
};

并添加虚拟析构函数。

这是正确的签名:

void push(std::unique_ptr<A> v) {
    //Perform some checks and other stuff before pushing
    push(std::move(v));
}
// It works for a because it has the right type but not for b
h.push(a);
这既是因为它是必需的,也是因为您希望更改所有权的代码变得清晰

请注意,
std::move(b)
代码将导致未定义的行为,因为
A
缺少虚拟析构函数

// It works for a because it has the right type but not for b
h.push(a);
此代码是有毒的,会导致错误。您只是默默地更改了
唯一的\u ptr
的所有权
auto_ptr
具有此属性,并且被发现几乎无法正确使用,因此被弃用,然后从标准中删除


对于
std::unique\u ptr
,不要编写使
unique\u ptr
行为类似于
auto\u ptr
的代码。对于
std::unique\u ptr
,您应该始终拥有所有权,在这种情况下,您不需要担心释放和生成新指针。相反,使用std::move
函数,它是为此而设计的。您可以将推送功能更改为:

void push (std::unique_ptr<A> v) { _items.push_back(std::move(v)); }

为什么不使用移动操作并允许协方差来完成所有这些呢。换句话说,丢失第一个实现,而不是第二个,正确地执行此操作。感谢您的洞察力!我会说:)如何不使用std::move调用unique_ptr的copy构造函数?@Masadow调用它的move构造函数。您可能想温习的移动语义。我必须承认,我大部分时间仍然坚持使用c++11之前的功能,我将阅读以下内容:)
void push (std::unique_ptr<A> v) { _items.push_back(std::move(v)); }
h.push(std::move(a));
h.push(std::move(b));