删除隐式转换的智能指针

时间:2016-12-01 15:01:14

标签: c++ smart-pointers implicit-conversion ambiguous

我正在阅读关于Scott Meyers的更有效的C ++ 的智能指针的第28项,并提出以下问题。

可以在http://ideone.com/aKq6C0找到完整的演示。

派生类指针可以隐式转换为基类指针:

class Base {};
class Derived : public Base {};
void foo(Base* b) { cout << "foo called on Base pointer" << endl;}
Derived *d = new Derived();
foo(d); //No problem

但智能指针不会发生这种隐式转换,即SmartPtr<Derived>无法隐式转换为SmartPtr<Base>。因此,我们使用成员模板进行此类转换:

template<typename T>
class SmartPtr {
public:
  //constructors, operator->, etc

  //member template for type conversion
  template<NewType>
  operator SmartPtr<NewType> () {
    return SmartPtr<NewType>(pointee);
  }
private:
  T* pointee;//the raw pointer
};

这几乎可以奏效,但可能导致含糊不清:

class Remote {};
class Base : public Remote {};
class Derived : public Base {};
void foo(const SmartPtr<Remote>& p) { cout << "remote" << endl;}
void foo(const SmartPtr<Base>& p) { cout << "base" << endl;}

SmartPtr<Derived> d(new Derived());
foo(d);//compile error: ambiguity

在此示例中,编译器不知道它是否应将d转换为SmartPtr<Base>SmartPtr<Remote>,尽管原始指针Base显然更优越。这本书说

  

我们所能做的最好的事情就是使用成员模板来生成转换函数,然后在出现歧义的情况下使用强制转换。

但我们究竟如何在这里申请演员? foo(static_cast<SmartPtr<Base>>(d))也没有编译。从错误消息我可以看出错误来自于SmartPtr的拷贝构造函数中使用非const引用。我想知道调用函数的正确方法是什么。

1 个答案:

答案 0 :(得分:0)

//constructors

这是你省略的最重要的部分:)

你的演员阵容是正确的,这完全取决于你拥有的一组构造函数。如果你有一个非const引用 - 你会得到你提到的错误,如果你可以将ref更改为复制ctor中的const并且代码将编译。

可能不是很明显,但是当你打电话时

return SmartPtr<NewType>(pointee);

您正在构建必须接受SmartPtr<NewType>的新T*,而NewTypeT是不同的类型。很可能你只有ctor接受相同类型的原始指针(例如T*SmartPtr<T>X*SmartPtr<X>)因此编译器正在寻找另一个SmartPtr( SmartPtr<T>&& other): pointee(other.pointee) { other.pointee = nullptr; } 创建新的SmartPtr并找到你的副本ctor,但它不能将新值绑定到非const ref

编辑:

如果您正在使用c ++ 11添加移动ctor也可以解决您的问题,因为它可以绑定到右值

{{1}}