我有以下代码,该代码是使用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
的情况。为什么会这样呢?可以采取什么措施来防止这种情况发生(除了根本不使用界面之外)?
答案 0 :(得分:2)
问题在于此功能:
void push(T& p) { q.push(p); }
这会复制p
,如果p
是std::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&)
。