实现接口时对已删除函数的unique_ptr引用

时间:2018-08-29 20:20:33

标签: c++ c++11 visual-c++

我有以下代码,该代码是使用MSVC2013工具链C ++ 11构建的(旧版本是工作约束函数):

template<class T>
class AbstractWrappedQueue {
public:
    virtual bool empty() = 0;
    virtual size_t size() = 0;
    virtual void push(T& value) = 0;
    virtual void push(T&& value) = 0;
    virtual T pop() = 0;
};

template<class T>
class WrappedQueue // : public AbstractWrappedQueue<T>
{
private:
    std::queue<T> q;
public:
    WrappedQueue() {}
    ~WrappedQueue() {}
    bool empty() { return q.empty(); }
    size_t size() { return q.size(); }
    void push(T& p) { q.push(p); }
    void push(T&& p) { q.push(std::move(p)); }
    T pop() {
        T r = std::move(q.front());
        q.pop();
        return r;
    }
};

WrappedQueue<std::unique_ptr<int>> ptr;

只要WrappedQueue独立存在,该类及其功能就可以毫无问题地与unique_ptr一起玩。但是,如果它实现了AbstractWrappedQueue接口(即,取消注释类定义的: AbstractWrappedQueue<T>部分,那么我会收到以下错误:

error C2280: 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function.

我不希望接口的应用程序导致可能发生尝试复制unique_ptr的情况。为什么会这样呢?可以采取什么措施来防止这种情况发生(除了根本不使用界面之外)?

1 个答案:

答案 0 :(得分:2)

问题在于此功能:

void push(T& p) { q.push(p); }

这会复制p,如果pstd::unique_ptr<int>,那将无法正常工作-无法复制。

如果您恰好拥有WrappedQueue<T>,则除非类模板的非virtual成员函数被实际使用,否则它们不会被实例化。因此,除非有人实际尝试push一个左值,否则这不是错误。这就是std::vector<T>::push_back(T const&)可以存在但仍然允许您拥有std::vector<std::unique_ptr<int>>的原因。很好-这只是当您尝试执行明显错误的操作时出现的错误。

但是,一旦拥有AbstractWrappedQueue<T>-具有虚拟成员函数,规则就会变得更加模糊:[temp.inst]/10

  

如果未以其他方式实例化虚拟成员函数,则不确定实现是否隐式实例化类模板的虚拟成员函数。

您的实现无论如何都将其实例化-该功能对于T=std::unique_ptr<int>而言格式不正确。因此出现了问题。

您可以通过不具有该虚拟功能或仅使用可复制类型来防止此情况。


旁注:您可能想要push(T const&),而不是push(T&)