开发者

Policies conversion works only with constructor

#include "stdafx.h"
#include <exception>

template<class T>
class NoCheck;

template<class T>
class EnforceNotNull
{
public:
    //EnforceNotNull(const NoCheck<T>&){}//<<-----If this is uncommented it works
    static void Check(T* p)
    {
        class NullPtrException : public std::exception
        {
        };

        if (!p)
        {
            throw NullPtrException();
        }
    }
};

template<class T>
class NoCheck
{
public:
    NoCheck(){}
    NoCheck(const NoCheck&){}
    NoCheck(const EnforceNotNull<T>&){}
    operator EnforceNotNull<T>() {return EnforceNotNull<T>();}//<<----开发者_Go百科-This seams to not do its job
    static void Check(T* p)
    {/*Empty body*/}
};


template<class T, template<class> class CheckingPolicy>
class SmartPtr : public CheckingPolicy<T>
{
public:
    SmartPtr(T* p)
    {
        Check(p);
    }

    template<class T1, template <class> class CheckingPolicy1>
    SmartPtr(const SmartPtr<T1,CheckingPolicy1>& pattern):pointee_(pattern.pointee_),
        CheckingPolicy<T>(pattern)
    {
    }
    T* pointee_;
private:

};

int _tmain(int argc, _TCHAR* argv[])
{

    SmartPtr<int,NoCheck> p1(nullptr);
    SmartPtr<int,EnforceNotNull> p = p1;//I'm trying here to convert NoCheck to    

   // EnforceNotNull but it works for me only if I use ctor, if I use conversion optor   
//(from  


  //  NoCheck to EnforceNotNull) it doesn't work why?
    return 0;
}


I don't see why the SmartPtr has to be inherited from the checking policy at all. Nor do I see why the policy has to be a template itself.

Why not simply:

#include <cstdlib>
#include <exception>

class EnforceNotNull
{
public:
    template <class T>
    static void Check(T* p)
    {
        class NullPtrException : public std::exception
        {
        };

        if (!p)
        {
            throw NullPtrException();
        }
    }
};


class NoCheck
{
public:
    template<class T>
    static void Check(T* p)
    {/*Empty body*/}
};


template<class T, class CheckingPolicy>
class SmartPtr
{
public:
    SmartPtr(T* p)
    {
        CheckingPolicy::Check(p);
    }

    template<class T1, class CheckingPolicy1>
    SmartPtr(const SmartPtr<T1,CheckingPolicy1>& pattern):pointee_(pattern.pointee_)
    {
        CheckingPolicy::Check(pointee_);  //pattern's pointee_ may not pass our check
    }
    T* pointee_;
private:

};

int main()
{

    SmartPtr<int,NoCheck> p1(NULL);
    SmartPtr<int,EnforceNotNull> p = p1;
    return 0;
}


Your operator EnforceNotNull<T>() function is not const, so the compiler isn't including it in the set of possible conversion functions. Uncomment EnforceNotNull copy ctor or put a const on the above function and your code should work.


Your code looks a little bit overcomplicated. For example, you don't have to inherit a policy unless it cares some state, which is not your case. Plus, having classes requires putting access specifiers, so you might be better off with structs.

Anyways, smart pointers cannot be copied, that is the main trick. You can only transfer ownership (movable concept). So your copy constructor is a bit incorrect. You may still have it if that is clearly your intent, but make sure you have some reference counter whatsoever.

Here is your code, simplified and working:

#include <cstdio>
#include <cstddef>
#include <exception>

class NullPtrException : public std::exception
{
};

template <typename T>
struct EnforceNotNull
{
    static void Check(T *p)
    {
        if (p == NULL)
        {
            throw NullPtrException();
        }
    }
};

template <typename T>
struct NoCheck
{
    static void Check(T *)
    {
    }
};


template <typename T, template <typename> class CheckingPolicy>
class SmartPtr
{
    T* pointee_;

public:
    SmartPtr (T* p) :
        pointee_ (p)
    {
        CheckingPolicy<T>::Check (pointee_);
    }

    template <typename T1, template <typename> class CheckingPolicy1>
    SmartPtr (SmartPtr<T1, CheckingPolicy1> & pattern) :
        pointee_ (pattern.get ())
    {
        CheckingPolicy<T>::Check (pointee_);
        pattern.release ();
    }

    ~SmartPtr ()
    {
        delete pointee_;
        pointee_ = NULL;
    }

    T *get ()
    {
        return pointee_;
    }

    T *release ()
    {
        T *result = pointee_;
        pointee_ = NULL;
        return result;
    }
};

int main()
{
    try
    {
        printf ("Creating NULL pointer...\n");
        SmartPtr<int, NoCheck> p1 (NULL);
        printf ("Changing policy... \n");
        SmartPtr<int, EnforceNotNull> p = p1;
        printf ("This doesn't work :-(\n");
    }
    catch (const NullPtrException &)
    {
        printf ("GOTCHA!!!\n");
    }
}

Here is how you enforce conversions using MPL:

#include <cstdio>
#include <cstddef>
#include <exception>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/or.hpp>

class NullPtrException : public std::exception {};

struct EnforceNotNull
{
    template <typename T>
    static void Check(T *p)
    {
        if (p == NULL)
            throw NullPtrException();
    }
};

struct NoCheck
{
    template <typename T>
    static void Check(T *) {}
};


template <typename T, typename CheckingPolicy>
class SmartPtr
{
    T* p_;

public:
    SmartPtr (T* p) :
        p_ (p)
    {
        CheckingPolicy::Check (p_);
    }

    template <typename T1, typename PolicyT>
    SmartPtr (SmartPtr<T1, PolicyT> & ptr,
              // Enable moving from no checking pointer to any pointer
              // or checking pointer to checking pointer.
              // This makes it impossible to transfer checking to non-checking pointer.
              typename boost::enable_if< boost::mpl::or_ <
              boost::is_same<PolicyT, NoCheck>,
              boost::is_same<PolicyT, CheckingPolicy> > >::type *dummy = NULL) :
        p_ (ptr.get ())
    {
        CheckingPolicy::Check (p_);
        ptr.release ();
    }

    ~SmartPtr ()
    {
        delete p_;
        p_ = NULL;
    }

    T *get () const
    {
        return p_;
    }

    T *release ()
    {
        T *result = p_;
        p_ = NULL;
        return result;
    }
};

int main()
{
    try
    {
        SmartPtr<int, NoCheck> p1 (NULL);
        SmartPtr<int, EnforceNotNull> p2 = p1;
        // SmartPtr<int, NoCheck> p3 = p2; // This will not compile.
    }
    catch (const NullPtrException &)
    {
        printf ("GOTCHA!!!\n");
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜