scoped_ptr for C++/CLI (ensure managed object properly frees owned native object) Motivating SO question: Is there a C++/CLI smart pointer project (e.g. scoped_ptr)?

I'm interested in any reviewer comments, and especially identified bugs or inconsistencies with the native scoped_ptr template after which this code is patterned.

#pragma once

/** @file clr_scoped_ptr.h
 ** @author R Benjamin Voigt (richardvoigt@gmail.com)
 ** 
 ** Rights reserved.  This code is not public domain.
 ** 
 ** Licensed under CC BY-SA 3.0             http://creativecommons.org/licenses/by-sa/3.0/
 **             or Lesser GPL 3 or later    http://www.gnu.org/copyleft/lesser.html
 ** with the following restrictions (per GPL section 7):
 **  - all warranties are disclaimed, and if this is prohibited by law, your sole remedy shall be recovery of the price you paid to receive the code
 **  - derived works must not remove this license notice or author attribution
 **  - modifications must not be represented as the work of the original author
 **  - attribution is required in the "about" or "--version" display of any work linked hereto, or wherever copyright notices are displayed by the composite work
 **/

struct safe_bool { private: safe_bool(); };

/** \brief C++/CLI analogue to boost::scoped_ptr, also similar to std::unique_ptr, for management of the lifetime of an unmanaged class instance by a managed object
 **/
template&lt;typename T&gt;
public ref class clr_scoped_ptr
{
    T* m_native_ptr;

    // declare copy-constructors and assignment operators to prevent double-free
    clr_scoped_ptr( clr_scoped_ptr&lt;T&gt;% ) /* = delete */ { throw gcnew System::InvalidOperationException("clr_scoped_ptr is non-copyable"); }

    template&lt;typename U&gt;
    clr_scoped_ptr( clr_scoped_ptr&lt;U&gt;% ) { throw gcnew System::InvalidOperationException("clr_scoped_ptr is non-copyable"); }

    clr_scoped_ptr% operator=( clr_scoped_ptr&lt;T&gt;% ) /* = delete */ { throw gcnew System::InvalidOperationException("clr_scoped_ptr is non-copyable"); }

    template&lt;typename U&gt;
    clr_scoped_ptr% operator=( clr_scoped_ptr&lt;U&gt;% ) { throw gcnew System::InvalidOperationException("clr_scoped_ptr is non-copyable"); }

public:
    clr_scoped_ptr( void ) : m_native_ptr(nullptr) {}
    explicit clr_scoped_ptr( T* ptr ) : m_native_ptr(ptr) {}
    !clr_scoped_ptr( void ) { reset(); }
    ~clr_scoped_ptr( void ) { clr_scoped_ptr::!clr_scoped_ptr(); }

    template&lt;typename U&gt;
    clr_scoped_ptr( U ptr ) : m_native_ptr(ptr) {}

    void reset( T* ptr ) { delete m_native_ptr; m_native_ptr = ptr; }
    void reset( void ) { reset(nullptr); }

    clr_scoped_ptr% operator=( T* ptr ) { reset(ptr); }

    template&lt;typename U&gt;
    clr_scoped_ptr% operator=( U ptr ) { reset(ptr); }

    operator struct safe_bool*() { return reinterpret_cast&lt;struct safe_bool*&gt;(m_native_ptr); }

    void swap( clr_scoped_ptr&lt;T&gt;% other )
    {
        using std::swap;
        swap(m_native_ptr, other.m_native_ptr);
    }

    T* release( void ) { T* retval = m_native_ptr; m_native_ptr = nullptr; return retval; }
    T* get( void ) { return m_native_ptr; }

    static T* operator-&gt;( clr_scoped_ptr&lt;T&gt;% sptr ) { return sptr.get(); }
    static T&amp; operator*( clr_scoped_ptr&lt;T&gt;% sptr ) { return *sptr.get(); }
};

template&lt;typename T&gt;
inline void swap( clr_scoped_ptr&lt;T&gt;% left, clr_scoped_ptr&lt;T&gt;% right )
{
    left.swap(right);
}
I have only superficially tested the code so far, but it seems to make sense. However, there are some details where I'm either missing something (which wouldn't surprise me, I'm more at home with C#) or the code is more complex than it needs to be. Any comments are appreciated!


The private copy constructors and assignment operators throw exceptions although they can never be called. Wouldn't it suffice to leave them empty?
The constructor and assignment operator both accept not only arguments of type T*, but also exist in a templated version taking U*. I can't quite figure out why. My first thought was that this allows pointers to derived types to be passed; but then again, this is also possible using just the first form.
Similarly, I don't understand the role of the template versions of the private constructor and assignment operator. From my understanding, neither of these will be auto-generated if you don't provide private versions.
The safe bool pattern sound like a great idea (I first had to research it). However, VS2010 shows a compile error saying "cannot convert from 'clr_scoped_ptr&lt;T&gt;::operator safe_bool *::safe_bool *' to 'safe_bool *'". Apparently, it treats the two occurrences of struct safe_bool as two different types. Am I missing something here?
You end the private methods and operators with a semicolon and you write empty argument lists as (void) rather than (). Are these just stylistic choices, or are there advantages in doing this?