0
\$\begingroup\$

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?

\$\endgroup\$
  • \$\begingroup\$ unique_ptr supports custom deleters. Though the deleter type will leak into the template arguments (which can be alleviated using a typedef). \$\endgroup\$ – ratchet freak Sep 23 '16 at 10:51
  • \$\begingroup\$ unique_ptr doesn't work because of the missing "fill" functionality. See stackoverflow.com/questions/12403750/… \$\endgroup\$ – Jan Rüegg Sep 23 '16 at 11:48
3
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ Thenks, very useful input! unique_ptr doesn't work because of the missing GetAddressOf function. I didn't know ComPtr, but this works quite well for cases where only a simple Release is needed, however not for custom release functions (for example if value_->Shutdown() has to be called instead of value_->Release()). Preventing a copy constructor is a very good point though. Also, I ended up adding an assert(value != nullptr) in the fill function, to avoid overriding a non-released pointer. \$\endgroup\$ – Jan Rüegg Sep 23 '16 at 13:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.