如何为运算符编写 c++ 智能指针 == / !=

How to write c++ smartpointer for operator == / !=

本文关键字:指针 智能 c++ 运算符      更新时间:2023-10-16

在我的项目中,我的框架中有一些机制,所以我自己设计了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(