The following class is a sort of "smart pointer" that can be used for automatically releasing pointers:
template <class Type>
class Releaser {
public:
Releaser(std::function<void(Type *)> function = [](Type *value) {
value->Release();
});
~Releaser();
Type *operator->();
Type &operator*();
Type *get();
Type **fill();
private:
Type *value_ = nullptr;
std::function<void(Type *)> function_;
};
template <class Type>
Releaser<Type>::Releaser(std::function<void(Type *)> function)
: function_(function) {}
template <class Type>
Releaser<Type>::~Releaser() {
if (value_) function_(value_);
}
template <class Type>
Type *Releaser<Type>::operator->() {
return value_;
}
template <class Type>
Type &Releaser<Type>::operator*() {
return *value_;
}
template <class Type>
Type *Releaser<Type>::get() {
return value_;
}
template <class Type>
Type **Releaser<Type>::fill() {
return &value_;
}
It can be used for example like this:
Releaser<IMFAttributes> attributes;
auto status = MFCreateAttributes(attributes.fill(), 1);
where MFCreateAttributes
has the following signature:
MFCreateAttributes(IMFAttributes** ppMFAttributes, unsigned int cInitialSize);
Do you see any way to improve this (e.g by getting rid of the std::function), or make it safer?
1 Answer 1
unique_ptr
has capability for custom deleters.
Besides that assuming you are doing this to deal with COM objects then you can use ComPtr and its GetAddressOf
If you define a destructor you should also define (or disallow in this case) the copy construct and copy assign. Failure to do so will result in dangling pointers and double frees:
Releaser<IMFAttributes> attributes;
auto status = MFCreateAttributes(attributes.fill(), 1);
{
Releaser<IMFAttributes> att = attributes;
} // att gets cleaned up
//attributes contains a dangling pointer
-
\$\begingroup\$ Thenks, very useful input! unique_ptr doesn't work because of the missing
GetAddressOf
function. I didn't knowComPtr
, but this works quite well for cases where only a simpleRelease
is needed, however not for custom release functions (for example ifvalue_->Shutdown()
has to be called instead ofvalue_->Release())
. Preventing a copy constructor is a very good point though. Also, I ended up adding anassert(value != nullptr)
in the fill function, to avoid overriding a non-released pointer. \$\endgroup\$Jan Rüegg– Jan Rüegg2016年09月23日 13:02:47 +00:00Commented Sep 23, 2016 at 13:02
unique_ptr
supports custom deleters. Though the deleter type will leak into the template arguments (which can be alleviated using a typedef). \$\endgroup\$