Invoke IDispose from C++

A major part of MediaLab is the “interop” layer between the managed C# code and the unmanaged C++ OpenCV layer.

This interop has some special constraints, but this post is about a more general-purpose issue between C# and C++: the try/finally construct. In C++ there is no such thing. Instead, they leverage the “automatic” scope finalization built into the language, i.e. “smart pointers” in their many forms.

The bad news is, std::unique_ptr and the gang do not accept ref class types as the type parameter, e.g. if I want to make a std::unique_ptr<Windows::Foundation::SomeType^> that does not compile.

Why is this important? In .NET there is the IDisposable interface, responsible for resource lifecycle. Programmers may use try/finally or the using construct to ensure it is invoked, regardless of exceptions. Neither of these constructs is viable in the C++/CX interop world, so instead, we need to “go with the flow” and leverage the automatic scope finalization built-in.

Why is this even something to worry about? Because eventually you obtain something that implements IDisposable and you “own” its lifecycle and must now ensure it is disposed under all circumstances!

This code is adopted from the final_act implementation, widely used as a “finalizer”. We just wanted to use that, but it also did not compile, so we just stripped it down. In C++/CX, the operator delete actually invokes the IDisposable machinery. In fact, you cannot even compile a call to Dispose()!

template <class F>
class disposer {
public:
	explicit disposer(F inst) noexcept :f_(inst), invoke_(true) {};
	~disposer() noexcept {
		if(invoke_) delete f_;
		invoke_ = false;
	}
	F operator->() const { return f_; }
private:
	F f_;
	bool invoke_;
};

As you can see, everything is hard-wired for simply invoking operator delete on the way out. A convenience override for operator-> makes it all work like butter!

// this invokes IDispose (via delete) at end-of-scope
disposer<BitmapBuffer^> bb(sb->LockBuffer(bbam));
IMemoryBufferReference^ imbr = bb->CreateReference();
...