tags:

views:

67

answers:

3
#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>();}//<<-----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;
}

Thanks.

+2  A: 

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;
}
UncleBens
I guess having policy as a template might help to avoid writing template <typename T>... for every method if there ever will be more than one.
Vlad Lazarenko
@UncleBens but your design has no control over allowing or not to convert from one type to another and that's the whole point of this example to allow or not conversion between NoCheck and EnforceNotNull.
There is nothing we can do
@A-ha: Then I misunderstood your intentions. So you want NoCheck not to be convertible to EnforceNotNull, because that would allow a `SmartPtr<T, EnforceNotNull>` to store a NULL pointer?
UncleBens
@UncleBens basically I want to have control over conversions. Either I will allow it or not. I decide. I'm sorry if it wasn't clear in the question (because probably wasn't).
There is nothing we can do
+1  A: 

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");
    }
}
Vlad Lazarenko
@Vlad You've missed the point. The point is that having inherited from policy I can later enforce compile time check on conversions between types with different policies. In your design it isn't the case. I agree that structs instead of classes is plausible choice.
There is nothing we can do
Well, that is not what you asked. To control conversions, you have to explicitly allow or disallow move constructor. It doesn't matter whether you do inheritance from policies or not, that is not necessary.
Vlad Lazarenko
OK, I extended my answer to cover compile-time conversion enforcements. So now you can convert from non-checking pointer to any pointer, but cannot convert checking to non-checking.
Vlad Lazarenko
@A-Ha: You should state what your intentions are in the question. People cannot just guess why you wrote your code (moreover when it is not required). From the code in the question it might even seem as if you wanted to allow transfer of policies (not that you can, but you are copy constructing one policy from an unrelated one). Also, it is not clear what the semantics for copy construction are. @Vlad is clear in his answer: move, but your code as it is written is incorrect as both `SmartPtr` keep raw pointers into the same object (if you intend on using reference counting that is not clear)
David Rodríguez - dribeas
+1  A: 

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.

Kristo
@Kristo That's my men. Great thanks.
There is nothing we can do