每个C/C++对象实例都应正确实现 IDisposable 接口,以确保对象实例能够正确释放持有的托管资源,而不仅仅只是依赖于 C++ RAII机制调用对象的析构函数。
这是因为并非所有的 C/C++ 对象,都通过析构函数来处理资源释放是正确的,例如:共享指针引用的 C/C++ 对象,且该对象需要一定时间才能完成资源的全部释放,这在多核并行编程上面是很常见的需求,这个时候依赖于析构处理,可能带来资源释放的不安全性。
本 IDisposable 接口类为 C/C++ 17 标准构建,允许用户调用实例的 Dispose 函数(若类成员 Dispose 函数不存在,即不调用,它是基于模板元编程实现的)
源实现:
cpp
class IDisposable : public Reference {
public:
template <typename T>
struct HAS_MEMBER_DISPOSE_FUNCTION {
private:
template <typename U>
static auto SFINAE_TEST(T*) -> decltype(std::declval<U>().Dispose(), std::true_type());
template <typename U>
static std::false_type SFINAE_TEST(...);
public:
static constexpr bool value = decltype(SFINAE_TEST<T>(NULL))::value;
};
template <typename T>
static bool Dispose(const T& obj) noexcept { /* CXX11: typename std::enable_if<HAS_MEMBER_DISPOSE_FUNCTION<T>::value, bool>::type */
if constexpr (std::is_pointer<T>::value) {
return DISPOSE_NPTR(obj);
}
if constexpr (stl::is_shared_ptr<T>::value) {
return DISPOSE_SPTR(obj);
}
elif constexpr (stl::is_unique_ptr<T>::value) {
return DISPOSE_UPTR(const_cast<T&>(obj));
}
elif constexpr (HAS_MEMBER_DISPOSE_FUNCTION<T>::value) {
return DISPOSE_COBJ(const_cast<T&>(obj));
}
else {
return false;
}
}
template <class... TReferences>
static void DisposeReferences(TReferences&&... objects) noexcept {
(IDisposable::Dispose(objects), ...);
}
public:
virtual void Dispose() noexcept = 0;
virtual ~IDisposable() noexcept = default;
private:
template <typename T>
static bool DISPOSE_COBJ(T& obj) noexcept {
if constexpr (HAS_MEMBER_DISPOSE_FUNCTION<T>::value) {
obj.Dispose();
return true;
}
return false;
}
template <typename T>
static bool DISPOSE_NPTR(T* obj) noexcept {
if constexpr (HAS_MEMBER_DISPOSE_FUNCTION<T>::value) {
if (obj) {
obj->Dispose();
return true;
}
}
return false;
}
template <typename T>
static bool DISPOSE_SPTR(const std::shared_ptr<T>& obj) noexcept {
if constexpr (HAS_MEMBER_DISPOSE_FUNCTION<T>::value) {
if (obj) {
obj->Dispose();
return true;
}
}
return false;
}
template <typename T>
static bool DISPOSE_UPTR(const std::unique_ptr<T>& obj) noexcept {
if constexpr (HAS_MEMBER_DISPOSE_FUNCTION<T>::value) {
if (obj) {
obj->Dispose();
return true;
}
}
return false;
}
};