I did an interesting experiment with C++/CLI. I need a way to store
unmanaged objects in a managed class in an exception safe way, and I
thought I would attempt to duplicate the functionality of
boost::scoped_ptr. Here's my preliminary code:
template <class T>
ref class ScopedPtr
{
typedef ScopedPtr<T> this_type;
public:
ScopedPtr()
: ptr(nullptr)
{
}
explicit ScopedPtr(T * p)
: ptr(p)
{
}
~ScopedPtr()
{
delete ptr;
}
T * get()
{
return ptr;
}
T & operator*()
{
return *ptr;
}
T * operator->()
{
return ptr;
}
void swap(ScopedPtr % other)
{
T * tmp = other.ptr;
other.ptr = ptr;
ptr = tmp;
}
void swap(ScopedPtr ^ other)
{
T * tmp = other->ptr;
other->ptr = ptr;
ptr = tmp;
}
void reset()
{
this_type().swap(this);
}
void reset(T * p)
{
this_type(p).swap(this);
}
private:
T * ptr;
ScopedPtr(const ScopedPtr %);
ScopedPtr % operator=(const ScopedPtr %);
};
The main differences between the original code and this one are the
following:
- It is a ref class, although it wraps an unmanaged class.
- There are no const functions in .NET, therefore get, operator* and
operator-> can not be const.
- swap uses a managed reference (%), not a regular &. Same with the copy
c'tor and assignment op. I had to implement a handle version of the
swap, which is based on "^" instead of "%". That's because "*this" calls
operator* automatically, which I think is a bug in the compiler. I'm not
that familiar with the standard, but IMO, *this should evaluate to a
"this_type %", instead of a call to operator*. I'm really not sure about
this.
- There's no default argument in .NET, so two separate c'tors had to be
created, and two reset functions.
It seems to be working nicely:
struct C
{
int i;
C(int value) : i(value) { }
void Do() { }
};
ref class RC
{
public:
ScopedPtr<C> c;
};
void Test()
{
ScopedPtr<C> c1;
ScopedPtr<C> c2(new C(0));
*c2 = 5;
c2->Do();
//c1 = c2; // this fails to compile, as it should
ce.reset();
}
What do you guys think? Is there any ratinale behind this? After all, GC
is not for unmanaged types, so exception safety is important there.
Tom