在我的项目中,我的框架中有一些机制,所以我自己设计了C++智能指针。
但是我遇到了智能指针的平等和不平等问题。
class Ref {
public:
void ref(){}
void unref(){}
};
template<class T>
class SmartPtr
{
public:
typedef T element_type;
SmartPtr() : _ptr(nullptr) {}
SmartPtr(T* ptr) : _ptr(ptr) { if (_ptr) _ptr->ref(); }
SmartPtr(const SmartPtr& rp) : _ptr(rp._ptr) { if (_ptr) _ptr->ref(); }
template<class Other>
SmartPtr(const SmartPtr<Other>& rp) : _ptr(rp._ptr)
{ if (_ptr) _ptr->ref(); }
~SmartPtr() { if (_ptr) _ptr->unref(); _ptr = 0; }
SmartPtr& operator = (const SmartPtr& rp)
{ assign(rp); return *this;}
template<class Other> SmartPtr& operator = (const SmartPtr<Other>& rp)
{ assign(rp); return *this;}
template<class Other> void assign(const SmartPtr<Other>& rp)
{_ptr=rp._ptr;}
operator T*() const { return _ptr; }
template<class U>
bool operator == (const SmartPtr<U>& rp) const
{ return (_ptr==rp._ptr); }
template<class U>
friend bool operator == (const U* ptr, const SmartPtr& rp)
{ return (ptr==rp._ptr); }
template<class U>
friend bool operator == (const SmartPtr& rp, const U* ptr)
{ return (ptr==rp._ptr); }
private:
template<class U> friend class SmartPtr;
T* _ptr;
};
当我编写以下代码时代码失败:
class A : public Ref {};
class B : public A {};
SmartPtr<A> a1 = new A;
A* a2 = a1;
bool flag = a1==a2; // ambiguous error, error message follows
SmartPtr<B> b = new B;
SmartPtr<A> a3 = b;
bool flag2 = a3==b; // build pass
编译错误消息
maybe "bool operator ==<A>(const U *,const ECB::SmartPtr<A> &)"
or "bool operator ==<A>(const U *,const ECB::SmartPtr<B> &)"
or "built-in C++ operator==(T1, T1)"
or "built-in C++ operator==(A *SmartPtr<A>::* , A *SmartPtr<A>::* )"
如何修改模板SmartPtr类以避免歧义错误?
使用 gcc 编译时,您会得到更清晰的错误消息:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
bool flag = a1==a2;
^~
note: candidate 1: 'bool operator==(const SmartPtr<T>&, const U*) [with U = A; T = A]'
friend bool operator == (const SmartPtr& rp, const U* ptr)
^~~~~~~~
note: candidate 2: 'operator==(A*, A*)' <built-in>
有两个候选人。您的声明:
template<class U>
friend bool operator == (const SmartPtr& rp, const U* ptr);
以及内置的将被a1.operator A*() == a2
调用(比较两个指针(。
要使用第一个,U
将被推导出为A
,但参数仍然const A*
,而你的指针是A*
。在第二个中,您的智能指针必须使用用户定义的转换(operator T*()
(转换为常规指针。
在这两种情况下,都存在转换(即使用户定义的转换通常比A*
转换为const A*
更差(。
问题是,当考虑第一个参数(智能指针(时,你的好友运算符是更好的匹配。但是对于第二个参数,内置参数是更好的匹配。GCC 通过使用"用户定义的转换运算符比A*
到const A*
更糟糕的转换"的逻辑来克服这一点,但这是一个非标准扩展(并随着-pedantic
而消失(。
解决方法是也有一个非常量重载:
template<class U>
friend bool operator == (const SmartPtr& rp, U* ptr)
{ return (ptr==rp._ptr); }
(您可以删除 const 重载,因为在这种情况下U
可以推断为const A
(