I wrote a class to implement auto_ptr Help me review this code:

#include &lt;iostream&gt;
#include &lt;cassert&gt;
using namespace std;

template &lt;typename T&gt;
class auto_ptr
{
public:
    explicit auto_ptr(T* p = NULL):m_p(p){}
    auto_ptr(auto_ptr&amp; other);
    auto_ptr&amp; operator=(auto_ptr&amp; other);
    T* get() const { return m_p; }
    void reset(T* p = NULL);
    T&amp; operator * (){ return *m_p; }
    T* operator -&gt; (){ return m_p; }
    ~auto_ptr()
    {
        if(m_p)
            delete m_p;
        m_p = NULL;
    }   
private:
    T* m_p;
    T* release();
};

int main()
{
    auto_ptr&lt;int&gt; p(new int(3));
    cout&lt;&lt;*p&lt;&lt;endl;

    int *b = new int(6);
    p.reset(b);
    cout&lt;&lt;*p.get()&lt;&lt;endl;

    auto_ptr&lt;int&gt; p1(new int(10));
    p = p1;
    cout&lt;&lt;*p&lt;&lt;endl;
    assert(NULL == p1.get());

    auto_ptr&lt;int&gt; p2(new int(100));
    auto_ptr&lt;int&gt;p3(p2);
    cout&lt;&lt;*p3&lt;&lt;endl;
    assert(NULL == p2.get());
}

template &lt;typename T&gt;
T* auto_ptr&lt;T&gt;::release()
{
    T* temp = this-&gt;m_p;
    this-&gt;m_p = NULL;
    return temp;
}

template &lt;typename T&gt;
auto_ptr&lt;T&gt;::auto_ptr(auto_ptr&amp; other)
{
    m_p = other.release();
}

template &lt;typename T&gt;
auto_ptr&lt;T&gt;&amp; auto_ptr&lt;T&gt;::operator=(auto_ptr&amp; other)
{   
    if(this == &amp;other)
        return *this;
    delete m_p;
    m_p = other.release();
    return *this;
}

template &lt;typename T&gt;
void auto_ptr&lt;T&gt;::reset(T* p)
{
    if(m_p != p)
    {
        delete m_p;
        m_p = p;    
    }
}
Assuming you are going to put this in a header file don't do thus

using namespace std;


See: https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice

These should be const as they don't change the state of your auto_ptr

T&amp; operator * (){ return *m_p; }
T* operator -&gt; (){ return m_p; }


The destructor

~auto_ptr()
{
    if(m_p)            // No need to check for NULL
                       // delete on a NULL pointer is valid.
        delete m_p;

    m_p = NULL;        // This is pointless.
                       // The object is about to leave scope.
}   


Why the sudden use of this!

template &lt;typename T&gt;
T* auto_ptr&lt;T&gt;::release()
{
    T* temp = this-&gt;m_p;
          //  ^^^^^^
    this-&gt;m_p = NULL;
 // ^^^^^^
    return temp;
}


Assignment not exception safe.

template &lt;typename T&gt;
auto_ptr&lt;T&gt;&amp; auto_ptr&lt;T&gt;::operator=(auto_ptr&amp; other)
{   
    if(this == &amp;other)
        return *this;

    // This is not exception safe.
    // T is completely unknown to you.
    // Therefore you must assume the person who wrote T is an idiot 
    // and therefore may throw an exception from there destructor.
    delete m_p;

    // If the above statement throws then your object is now in an undefined
    // state with m_p pointing at an invalid object.


    m_p = other.release();
    return *this;
}


The correct way to do this.

template &lt;typename T&gt;
auto_ptr&lt;T&gt;&amp; auto_ptr&lt;T&gt;::operator=(auto_ptr&amp; other)
{   
    if(this == &amp;other)
        return *this;

    auto_ptr&lt;T&gt; tmp = release();
    m_p = other.release();

    // After the state of your (and other objects)
    // are completely defined and are in a good state.
    // then you can tidy up any left over objects.

    return *this;

    // the destructor of tmp should now release it properly.
}