Click here to Skip to main content
15,945,939 members
Articles / Programming Languages / C++

CAutoNativePtr - A managed smart pointer for using native objects in managed code

Rate me:
Please Sign up or sign in to vote.
4.98/5 (31 votes)
20 Jan 2006Ms-PL3 min read 76.3K   929   35   6
CAutoNativePtr is a managed template class that acts as a smart pointer, and is handy for using native objects in managed code.

Overview

CAutoNativePtr is a managed template class that acts as a smart pointer, and is handy for using native objects in managed code.

MC++
template
<
  typename T
> 
ref class CAutoNativePtr

Here, T is the native type that's wrapped. The class manages a smart pointer, which will automatically free the native resource when it falls out of scope or the containing managed object is finalized during garbage collection. The copy constructors and assignment operators transfer ownership, which means that only one CAutoNativePtr can own a specific native object at any time (unless you write buggy code that directly overrides this rule).

Using the class

Here's some sample code that shows how the class can be used.

MC++
class Native
{
public:
    void F()
    {
    }
};

class Derived : public Native{};

void SomeFunc(Native){} //Function takes a Native object
void SomeOtherFunc(Native*){} //Function takes a Native*

ref class Ref
{
    CAutoNativePtr<Native> m_native; //Declare the smart pointer object
public:
    Ref()
    {		
    }

    Ref(Native* pN) : m_native(pN) //Constructor that takes a T*
    {
    }

    //Copy constructor comes into play here
    Ref(CAutoNativePtr<Native> pN) : m_native(pN)
    {
    }

    //Assigning from a T*
    void Change(Native* pNew)
    {
        m_native = pNew;
    }

    //Assigning from another smart pointer
    void Change(CAutoNativePtr<Native> pNew)
    {
        m_native = pNew;
    }

    void DoStuff()
    {
        if(!m_native) // Logical NOT applied via T* cast
        {
        }
        else
        {
            m_native->F(); //-> operator at work here
            SomeFunc(*m_native); //The T* cast at work
            SomeOtherFunc(m_native); //The T* cast at work
        }
    }

    bool DoComparisons(CAutoNativePtr<Native> a1, 
        CAutoNativePtr<Native> a2, CAutoNativePtr<Native> a3)
    {
        //Operators == and != applied via T* cast
        return (a1 == a2) && (a1 != a3);		
    }

    void Close()
    {
        m_native.Destroy(); //Free native resource
    }
};

int main()
{		
    CAutoNativePtr<Derived> d1(new Derived); 
    CAutoNativePtr<Derived> d2(new Derived);

    //Specialized constructor for derived types is called here
    CAutoNativePtr<Native> n1(d1);

    //Specialized assignment operator for derived types is called here
    n1 = d2;

    return 0;
}

Class Reference

Methods

CAutoNativePtr - The constructor

There are four overloads that you can use.

  • CAutoNativePtr()
  • CAutoNativePtr(T* t)
  • CAutoNativePtr(CAutoNativePtr<T>% an)
  • template<typename TDERIVED> CAutoNativePtr(CAutoNativePtr<TDERIVED>% an)

The parameter-less constructor creates a CAutoNativePtr that wraps a nullptr object of type T. The overload that takes a T* can be used to wrap an existing pointer. Then, there are two copy constructor overloads, where one of them is to copy construct from a CAutoNativePtr<T> (same type) and the other is to copy construct from a CAutoNativePtr<TDERIVED> (which wraps a derived type of T). When you copy construct a CAutoNativePtr object, the source object's T* is detached, because only one CAutoNativePtr should own a T* at any given time, else we end up with double deletion.

~CAutoNativePtr/!CAutoNativePtr - Destructor and Finalizer

  • !CAutoNativePtr()
  • ~CAutoNativePtr()

The allocated object (if any) is freed. By having the destructor invoke the finalizer, both stack semantics and non-deterministic garbage collection are supported.

Attach - To take over an existing T*

  • void Attach(T* t)

The CAutoNativePtr will take ownership of the T*, and if there's an existing T*, it will be deleted.

Detach - Release the T*

  • T* Detach()

The underlying T* is released, and it's up to the caller to free the object now.

Destroy - Delete the underlying T*

  • void Destroy()

The underlying T* is deleted. Once you make this call, the CAutoNativePtr does not own any object any more.

Operators

operator-> - Pointer to member operator

  • static T* operator->(CAutoNativePtr<T>% an)

This returns the underlying T* object and allows the user to access T methods and fields by using the -> operator.

operator T* - Cast to T*

  • static operator T*(CAutoNativePtr<T>% an)

This is a cast to the underlying T*. This means you can pass a CAutoNativePtr object where a T* is expected, which is pretty convenient.

operator= - Assignment operator

There are three overloads for the assignment operator.

  • CAutoNativePtr<T>% operator=(T* t)
  • CAutoNativePtr<T>% operator=(CAutoNativePtr<T>% an)
  • template<typename TDERIVED> CAutoNativePtr<T>% operator=(CAutoNativePtr<TDERIVED>% an)

The first one takes a T*. If the CAutoNativePtr currently owns a T*, that's released before ownership of the new T* is taken. The other two overloads are for assignment from CAutoNativePtr objects, where one of them is specialized to handle a CAutoNativePtr object that owns a T derived object. When ownership is taken, it's transferred, which means the source objects loses ownership of the T*, and this is done to avoid double-deletion.

History

  • January 19th, 2006 : Article and code first published

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
United States United States
Nish Nishant is a technology enthusiast from Columbus, Ohio. He has over 20 years of software industry experience in various roles including Chief Technology Officer, Senior Solution Architect, Lead Software Architect, Principal Software Engineer, and Engineering/Architecture Team Leader. Nish is a 14-time recipient of the Microsoft Visual C++ MVP Award.

Nish authored C++/CLI in Action for Manning Publications in 2005, and co-authored Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on CodeProject.com and another 250+ blog articles on his WordPress blog. Nish is experienced in technology leadership, solution architecture, software architecture, cloud development (AWS and Azure), REST services, software engineering best practices, CI/CD, mentoring, and directing all stages of software development.

Nish's Technology Blog : voidnish.wordpress.com

Comments and Discussions

 
QuestionCatch with delete Pin
guy_montag15-Nov-17 23:42
guy_montag15-Nov-17 23:42 
Generalmissing namespace Pin
hofingerandi13-May-11 0:13
hofingerandi13-May-11 0:13 
GeneralExport CAutoNativePtr from one C++/CLI DLL to another Pin
andyb197922-May-09 5:56
andyb197922-May-09 5:56 
GeneralRef class usage Pin
Robin Imrie22-Feb-06 6:05
professionalRobin Imrie22-Feb-06 6:05 
Newsmsclr::auto_ptr (STL-like solution) Pin
DS2-Feb-06 1:03
DS2-Feb-06 1:03 
Hello, Nishant,

Thanks for your excellent article.

I prepare STL-like solution for using native objects in managed code. It is similar to the msclr::auto_handle<> and msclr::auto_gcroot<> types implementation style. See my code below.

Best Regards,
Denis N. Shevchenko


==================================================
msclr_auto_ptr.h
==================================================

/***************************************************************
*
* Module Name:
* msclr_auto_ptr.h
*
* Abstract:
* A auto pointer that can be used as a member of
* a CLR class.
*
* Author:
* Denis N. Shevchenko [dsheva@gmail.com] 1-Feb-2006
*
* License:
* You may freely use and modify this class as long as you
* include this copyright.
*
* This code is provided "as is" without express
* or implied warranty.
*
* Copyright © Denis N. Shevchenko, 2006.
*
***************************************************************/

#pragma once

#include <msclr\safebool.h>
#include <assert.h>


namespace msclr
{


template<class T>
ref class auto_ptr
{
public:
typedef T element_type;

public:
auto_ptr() /*throw()*/
: p_(0)
{
}

explicit auto_ptr(T *p) /*throw()*/
: p_(p)
{
}

auto_ptr(auto_ptr<T> %rhs) /*throw()*/
: p_(rhs.release())
{
}

template<class T2>
auto_ptr(auto_ptr<T2> %rhs) /*throw()*/
: p_(rhs.release())
{
}

~auto_ptr() /*throw()*/
{
delete p_;
}

!auto_ptr() /*throw()*/
{
using namespace std;
assert(("msclr::auto_ptr<> : Finalizer used! The variable deleted in non-deterministic way.", false));

delete p_;
}

public:
template<class T2>
operator auto_ptr<T2>() /*throw()*/
{
return auto_ptr<T2>(*this);
}

auto_ptr<T>% operator=(auto_ptr<T> %rhs) /*throw()*/
{
reset(rhs.release());
return *this;
}

template<class T2>
auto_ptr<T>% operator=(auto_ptr<T2> %rhs) /*throw()*/
{
reset(rhs.release());
return *this;
}

static T& operator*(auto_ptr %ap) /*const throw()*/
{
if(!ap.p_)
throw gcnew System::NullReferenceException("msclr::auto_ptr<>");
return *ap.p_;
}

T* operator->() /*const throw()*/
{
return &**this;
}

public:
T* get() /*const throw()*/
{
return p_;
}

T* release() /*throw()*/
{
T *p = p_;
p_ = 0;
return p;
}

void reset() /*throw()*/
{
reset(0);
}

void reset(T *p) /*throw()*/
{
if(p != p_)
delete p_;
p_ = p;
}

// Additional functionality like in msclr::auto_handle
public:
void swap(auto_ptr<T> %rhs) /*throw()*/
{
auto_ptr<T> tmp = rhs;
rhs = *this;
*this = tmp;
}

// for use when auto_ptr appears in a conditional
operator _detail_class::_safe_bool() /*throw()*/
{
return p_ != 0 ? _detail_class::_safe_true : _detail_class::_safe_false;
}

// for use when auto_ptr appears in a conditional
bool operator!() /*throw()*/
{
return p_ == 0;
}

private:
T *p_;
};


template<typename T>
void swap(auto_ptr<T> %lhs, auto_ptr<T> %rhs)
{
lhs.swap(rhs);
}


} // namespace msclr

GeneralRe: msclr::auto_ptr (STL-like solution) Pin
Nish Nishant2-Feb-06 1:42
sitebuilderNish Nishant2-Feb-06 1:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.