C++;我应该使用自动资源管理吗? 我是一个C++业余爱好者。我正在编写一些Win32 API代码,其中有大量句柄和奇怪的组合分配对象。所以我想知道-是否有一些包装类可以使资源管理更容易

C++;我应该使用自动资源管理吗? 我是一个C++业余爱好者。我正在编写一些Win32 API代码,其中有大量句柄和奇怪的组合分配对象。所以我想知道-是否有一些包装类可以使资源管理更容易,c++,raii,resource-management,C++,Raii,Resource Management,例如,当我想加载一些数据时,我用CreateFile()打开一个文件,并获得一个句柄。完成后,我应该对其调用CloseHandle()。但对于任何合理复杂的加载函数,都会有几十个可能的退出点,更不用说异常了 因此,如果我能将句柄包装在某种包装类中,当执行离开作用域时,它会自动调用CloseHandle(),那就太好了。更好的是,它可以进行一些引用计数,这样我就可以在其他函数中来回传递它,并且只有当最后一个引用离开作用域时,它才会释放资源 这个概念很简单,但是在标准库中有类似的东西吗?顺便说一下,

例如,当我想加载一些数据时,我用
CreateFile()
打开一个文件,并获得一个
句柄。完成后,我应该对其调用
CloseHandle()
。但对于任何合理复杂的加载函数,都会有几十个可能的退出点,更不用说异常了

因此,如果我能将句柄包装在某种包装类中,当执行离开作用域时,它会自动调用
CloseHandle()
,那就太好了。更好的是,它可以进行一些引用计数,这样我就可以在其他函数中来回传递它,并且只有当最后一个引用离开作用域时,它才会释放资源


这个概念很简单,但是在标准库中有类似的东西吗?顺便说一下,我使用Visual Studio 2008,我不想附加像Boost之类的第三方框架。

MFC有一些合适的图元(例如,),但不是标准库。

本质上,<代码> fStuts是一个很好的文件句柄C++包。它是标准的一部分,这意味着它是可移植的、经过良好测试的,并且以面向对象的方式可扩展。对于文件资源来说,这是一个很好的概念


< > > <>代码> fStuts只适用于文件,而不是通用句柄,即线程、进程、同步对象、内存映射文件等。

Visual C++ 2008通过特征包支持Tr1,Tr1包含SyrdY-PTR。我会使用它——它是一个非常强大的智能指针类,可以推广到您要求的资源管理类型


TR1实际上是标准的扩展。我相信它仍然是官方的“标准前”,但实际上你可以认为它被锁定了。这只是几行代码。这只是一个简单的任务,不值得提供一个通用的可重用版本

struct FileWrapper {
  FileWrapper(...) : h(CreateFile(...)) {}
  ~FileWrapper() { CloseHandle(h); }

private:
  HANDLE h;
};
考虑一下泛型版本必须做什么:它必须是可参数化的,这样您就可以指定任意一对函数,以及任意数量的参数。仅实例化这样一个对象可能需要与上述类定义一样多的代码行

当然,C++0x添加lambda表达式可能会在某种程度上打破平衡。两个lambda表达式可以很容易地传递给一个通用包装器类,所以一旦C++0x支持出现,我们可能会看到这样一个通用RAII类被添加到Boost或其他东西中

但是现在,只要你需要它,你就可以更容易地自己滚动

至于增加参考计数,我建议不要这样做。引用计数非常昂贵(突然之间,您的句柄必须被动态分配,并且在每次分配时都必须维护引用计数器),而且很难做到正确。这是一个在线程环境中充满微妙竞争条件的领域


如果您确实需要引用计数,只需执行类似于
boost::shared\u ptr
:在
shared\u ptr

中包装您的自定义即席RAII类,下面是一个基于“Windows通过C/C++”的EnsureCleanup代码的类:

我认为标准库中没有任何东西,我也怀疑是否可以使用共享指针(如boost中的)因为这些指针应该是句柄,而不是句柄

按照习惯用法(如果您愿意,还可以使用模板/函数指针等)自己编写一个模板应该不难。

template
类唯一句柄
{
使用pointer=typename Traits::pointer;
指针m_值;
自动关闭()抛出()->void
{
如果(*本)
{
特征:接近(m_值);
}
}
公众:
唯一句柄(唯一句柄常量&)=删除;
自动运算符=(唯一句柄常量&)->唯一句柄&=delete;
显式唯一_句柄(指针值=Traits::invalid())throw():
m_值{value}
{
}
唯一\u句柄(唯一\u句柄和其他)throw():
m_值{other.release()}
{
}
自动运算符=(唯一句柄和其他)throw()->唯一句柄&
{
如果(此!=&其他)
{
重置(其他.释放());
}
归还*这个;
}
~unique_handle()throw()
{
close();
}
显式运算符bool()const throw()
{
返回m_值!=Traits::invalid();
}
自动获取()常量抛出()->指针
{
返回m_值;
}
自动获取()throw()->指针的地址*
{
断言(!*此);
返回&m_值;
}
自动释放()抛出()->指针
{
自动值=m_值;
m_值=特征::无效();
返回值;
}
自动重置(指针值=Traits::invalid())throw()->bool
{
如果(m_值!=值)
{
close();
m_值=值;
}
返回静态_cast(*此);
}
自动交换(唯一句柄和其他)throw()->void
{
标准::交换(m_值,其他.m_值);
}
};
模板
自动交换(独特的手柄和左侧,
唯一的_句柄(右)throw()->void
{
左。交换(右);
}
模板
自动运算符==(唯一句柄常量和左,
唯一的_handle const(右)throw()->bool
{
返回left.get()==right.get();
}
模板
汽车操作员=(独特的把手常数和左侧,
唯一的_handle const(右)throw()->bool
{
返回left.get()!=right.get();
}
模板
自动操作员布尔
{
返回left.get()=(唯一句柄常量和左侧,
唯一的_handle const(右)throw()->bool
{
返回left.get()>=right.get();
}
模板
自动操作员>(唯一手柄常数和左侧,
唯一的\u句柄常量(右)throw()->b
template <typename Traits>
class unique_handle
{
    using pointer = typename Traits::pointer;

    pointer m_value;

    auto close() throw() -> void
    {
        if (*this)
        {
            Traits::close(m_value);
        }
    }

public:

    unique_handle(unique_handle const &) = delete;
    auto operator=(unique_handle const &)->unique_handle & = delete;

    explicit unique_handle(pointer value = Traits::invalid()) throw() :
        m_value{ value }
    {
    }

    unique_handle(unique_handle && other) throw() :
        m_value{ other.release() }
    {
    }

    auto operator=(unique_handle && other) throw() -> unique_handle &
    {
        if (this != &other)
        {
            reset(other.release());
        }

        return *this;
    }

    ~unique_handle() throw()
    {
        close();
    }

    explicit operator bool() const throw()
    {
        return m_value != Traits::invalid();
    }

    auto get() const throw() -> pointer
    {
        return m_value;
    }

    auto get_address_of() throw() -> pointer *
    {
        ASSERT(!*this);
        return &m_value;
    }

    auto release() throw() -> pointer
    {
        auto value = m_value;
        m_value = Traits::invalid();
        return value;
    }

    auto reset(pointer value = Traits::invalid()) throw() -> bool
    {
        if (m_value != value)
        {
            close();
            m_value = value;
        }

        return static_cast<bool>(*this);
    }

    auto swap(unique_handle<Traits> & other) throw() -> void
    {
        std::swap(m_value, other.m_value);
    }
};

template <typename Traits>
auto swap(unique_handle<Traits> & left,
    unique_handle<Traits> & right) throw() -> void
{
    left.swap(right);
}

template <typename Traits>
auto operator==(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() == right.get();
}

template <typename Traits>
auto operator!=(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() != right.get();
}

template <typename Traits>
auto operator<(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() < right.get();
}

template <typename Traits>
auto operator>=(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() >= right.get();
}

template <typename Traits>
auto operator>(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() > right.get();
}

template <typename Traits>
auto operator<=(unique_handle<Traits> const & left,
    unique_handle<Traits> const & right) throw() -> bool
{
    return left.get() <= right.get();
}

struct null_handle_traits
{
    using pointer = HANDLE;

    static auto invalid() throw() -> pointer
    {
        return nullptr;
    }

    static auto close(pointer value) throw() -> void
    {
        VERIFY(CloseHandle(value));
    }
};

struct invalid_handle_traits
{
    using pointer = HANDLE;

    static auto invalid() throw() -> pointer
    {
        return INVALID_HANDLE_VALUE;
    }

    static auto close(pointer value) throw() -> void
    {
        VERIFY(CloseHandle(value));
    }
};

using null_handle = unique_handle<null_handle_traits>;
using invalid_handle = unique_handle<invalid_handle_traits>;