自己的智能指针的模板特化

Posted

技术标签:

【中文标题】自己的智能指针的模板特化【英文标题】:Template specialization for own smart pointer 【发布时间】:2017-10-07 21:00:46 【问题描述】:

我有自己的智能指针类实现。

template<class Pointee>
class SmartPtr 
private:
    Pointee* _pointee;
    SmartPtr(SmartPtr &);
public:
    explicit SmartPtr(Pointee * pt = 0);
    ~SmartPtr();
    SmartPtr& operator=(SmartPtr&);
    operator Pointee*() const  return _pointee; 
    bool operator!() const  return _pointee != 0; 
    bool defined() const  return _pointee != 0; 
    Pointee* operator->() const  return _pointee; 
    Pointee& operator*() const  return *_pointee; 
    Pointee* get() const  return _pointee; 
    Pointee* release();
    void reset(Pointee * pt = 0);
;

template<class Pointee>
class SmartPtr<SmartPtr<Pointee>> 
private:
    Pointee* _pointee;
    SmartPtr(SmartPtr &);
public:
    explicit SmartPtr(SmartPtr<Pointee> * pt = 0);
    ~SmartPtr();
    SmartPtr& operator=(SmartPtr&);
    operator Pointee*() const  return *_pointee; 
    bool operator!() const  return _pointee != 0; 
    bool defined() const  return _pointee != 0; 
    Pointee& operator->() const  return _pointee; 
    Pointee& operator*() const  return *_pointee; 
    Pointee* get() const  return _pointee; 
    Pointee* release();
    void reset(Pointee * pt = 0);
;

template<class Pointee>
SmartPtr<Pointee>::SmartPtr(SmartPtr &spt) :_pointee(spt.release()) 
    return;


template<class Pointee>
SmartPtr<Pointee>::SmartPtr(Pointee * pt) : _pointee(pt) 
    return;


template<class Pointee>
SmartPtr<SmartPtr<Pointee>>::SmartPtr(SmartPtr<Pointee>* pt) : _pointee(pt) 
    return;


template<class Pointee>
SmartPtr<Pointee>::~SmartPtr() 
    delete _pointee;


template<class Pointee>
SmartPtr<Pointee>& SmartPtr<Pointee>::operator=(SmartPtr &source)

    if (&source != this)
        reset(source.release());
    return *this;


template<class Pointee>
Pointee * SmartPtr<Pointee>::release() 
    Pointee* oldSmartPtr = _pointee;
    _pointee = 0;
    return oldSmartPtr;


template<class Pointee>
void SmartPtr<Pointee>::reset(Pointee * pt) 
    if (_pointee != pt)
    
        delete _pointee;
        _pointee = pt;
    
    return;

这个想法是我可以做到这一点:

SmartPtr<SmartPtr<SmartPtr<Time>>> sp3(new SmartPtr<SmartPtr<Time>>(new SmartPtr<Time>(new Time(0, 0, 1))));

Time 这是我自己的测试类。它有方法hours(),它显示在我在构造函数中设置的控制台小时数。

我可以像这样在控制台中显示小时数:

cout << sp2->hours() << endl;

代替:

cout << sp3->operator->()->operator->()->hours() << endl;

我可以这样做,因为我有头等舱,在 opertor-&gt;() 我返回 Pointee*

template<class Pointee>
    class SmartPtr ...

还有

template<class Pointee>
class SmartPtr<SmartPtr<Pointee>> ...

opertor-&gt;() 我返回Pointee &amp;

但有些错误我无法修复。

Error C2440 initialization: can not be converted "SmartPtr<Time> *" in "Time *" 
Error C2439 SmartPtr<SmartPtr<Time>>::_pointee: unable to initialize member

【问题讨论】:

你为什么想要这些? 只是为了好玩,但我坚持这个问题 对我来说一点也不好玩。更像是火车残骸。 【参考方案1】:

如果你真的想获得一个 operator-&gt;() 递归提取 SmartPtr 以获得内部 no-SmartPtr 指针......我认为你应该避免专门化 SmartPtr 类,为 @987654325 @模板参数,但你必须“专门化”operator-&gt;()

我是说……

(1) 删除SmartPtr&lt;SmartPtr&lt;Pointee&gt;&gt; 特化

(2) 在SmartPtr 实现之前,开发一个type-traits 来检测Pointee 是否是SmartPtr,例如

template <typename>
class SmartPtr;

template <typename>
struct isSP : public std::false_type
  ;

template <typename P>
struct isSP<SmartPtr<P>> : public std::true_type
  ;

(3) 要求operator-&gt;()真正执行到你通过标签调度选择的另一个函数,例如

auto const operator->() const
  return getPtr(isSP<Pointee>); 

(4)通过示例实现不同版本的分派函数,在真情况下递归,在假情况下返回指针

auto const getPtr (std::true_type const &) const 
  return _pointee->operator->(); 

auto const getPtr (std::false_type const &) const 
  return _pointee; 

现在(main())你可以写`

std::cout << sp3->hours() << std::endl;

(但你确定这是个好主意吗?)

无论如何...不幸的是,此解决方案使用 getPtr()operator-&gt;()auto 返回类型,因此仅适用于 C++14;如果你想要一个 C++11(或 C++98)的解决方案,那就有点复杂了。

以下是一个完整的工作示例

#include <iostream>
#include <type_traits>

template <typename>
class SmartPtr;

template <typename>
struct isSP : public std::false_type
  ;

template <typename P>
struct isSP<SmartPtr<P>> : public std::true_type
  ;

template<class Pointee>
class SmartPtr 
private:
    Pointee* _pointee;
    SmartPtr(SmartPtr &);
public:
    explicit SmartPtr(Pointee * pt = 0);
    ~SmartPtr();
    SmartPtr& operator=(SmartPtr&);
    operator Pointee*() const  return _pointee; 
    bool operator!() const  return _pointee != 0; 
    bool defined() const  return _pointee != 0; 


    auto const getPtr (std::true_type const &) const 
      return _pointee->operator->(); 

    auto const getPtr (std::false_type const &) const 
      return _pointee; 

    auto const operator->() const
      return getPtr(isSP<Pointee>); 


    Pointee& operator*() const  return *_pointee; 
    Pointee* get() const  return _pointee; 
    Pointee* release();
    void reset(Pointee * pt = 0);
;

template<class Pointee>
SmartPtr<Pointee>::SmartPtr(SmartPtr &spt) :_pointee(spt.release()) 
    return;


template<class Pointee>
SmartPtr<Pointee>::SmartPtr(Pointee * pt) : _pointee(pt) 
    return;


template<class Pointee>
SmartPtr<Pointee>::~SmartPtr() 
    delete _pointee;


template<class Pointee>
SmartPtr<Pointee>& SmartPtr<Pointee>::operator=(SmartPtr &source)

    if (&source != this)
        reset(source.release());
    return *this;


template<class Pointee>
Pointee * SmartPtr<Pointee>::release() 
    Pointee* oldSmartPtr = _pointee;
    _pointee = 0;
    return oldSmartPtr;


template<class Pointee>
void SmartPtr<Pointee>::reset(Pointee * pt) 
    if (_pointee != pt)
    
        delete _pointee;
        _pointee = pt;
    
    return;



struct Time
 
   int a, b, c;

   Time (int a0, int b0, int c0) : aa0, bb0, cc0
     

   int hours () const
     return a; 
 ;


int main ()
 
   SmartPtr<SmartPtr<SmartPtr<Time>>>
      sp3(new SmartPtr<SmartPtr<Time>>(new SmartPtr<Time>(new Time(0, 0, 1))));

   std::cout << sp3->hours() << std::endl;    
 

【讨论】:

【参考方案2】:

在第 50 行你有:

SmartPtr<SmartPtr<Pointee>>::SmartPtr(SmartPtr<Pointee>* pt) : _pointee(pt) 

应该是这样的

SmartPtr<SmartPtr<Pointee>>::SmartPtr(SmartPtr<Pointee>* pt) : _pointee(pt->get()) 

此外,您的专用 SmartPtr-to-SmartPtr 版本似乎缺少析构函数实现。

但最后不得不说

你在这里做的都是错的。这是糟糕的、令人困惑的代码,我强烈建议您不要使用它。

【讨论】:

以上是关于自己的智能指针的模板特化的主要内容,如果未能解决你的问题,请参考以下文章

C++模板的特化与偏特化

C++模板类模板的全部特例化和局部特例化(偏特化-partial specialization)

为啥可变参数模板的模板特化与非可变模板的特化不同?

模板的全特化与偏特化

C++模板详解:泛型编程模板原理非类型模板参数模板特化分离编译

C++模板详解:泛型编程模板原理非类型模板参数模板特化分离编译