【问题标题】:More complex cleanup in C++C++ 中更复杂的清理
【发布时间】:2014-04-19 19:14:12
【问题描述】:

我非常了解 RAII 模式和 std::unique_ptr 以及 C++11 中的其他“智能指针”,但仍有一些情况我无法弄清楚如何在没有 goto Cleanup 的情况下很好地处理最后进行清理的部分。

具体来说,我正在考虑 Windows 编程,有时我会想要泄漏句柄,而其他时候我不会。

如果我有一个类似于他的函数:

PROCESS_INFORMATION p;
if (!CreateProcess(... &p))
{
  throw windows_error(GetLastError());
}

DWORD r = WaitForSingleObject(h, 5000);
if (r == WAIT_TIMEOUT || r == WAIT_FAILED)
{
  // terminate process, close handles
  throw ...;
}

if (!SetEnvironmentVariable(...))
{
  // terminate process, close handles
  throw windows_error;
}

(a few other operations that if they fail i have cleanup to do).

return process handle;

我真的不明白unique_ptr 在这里如何帮助我,除非我在unique_ptr 上使用release(),毕竟if 表示成功/告诉@987654329 @不清理它。 (我可以为unique_ptr 创建一个特殊的删除器,这样它就可以正确清理窗口句柄)。但是,我的问题是,在我想将分配的内存/句柄泄漏回调用者的情况下,在智能指针上使用release() 是“正确的”吗?有更好的方法吗?返回shared_ptr 也可以,我想...

【问题讨论】:

  • 当你说“泄漏给调用者”时,你是在说函数的返回值吗?
  • 在我现在的特殊情况下,我将它保存到我班级的私有 HANDLE 字段中。但是,是的,一般来说,我只是指调用者,或者“超出函数范围的生命周期”。
  • 代码下的描述听起来很像著名的Scope Guard (Alexandrescu/Marginean)。 Here's the original article 但有更好的 C++11 实现。但是,构建/使用一个单独负责管理该 Process 资源的类可能更合适。

标签: c++11 raii resource-cleanup


【解决方案1】:

当您想从函数中传递资源时,有两种情况:资源可复制(它具有可访问的复制构造函数)或不可复制。

如果资源是可复制的(例如shared_ptr),那么您只需将其复制到它需要去的任何地方就可以了。当您的函数返回时,只有您的资源副本被销毁。

如果资源不可复制(例如unique_ptr),那么您需要移动它,这就是C++ 11 中的move semantics 的意义所在。

当你将资源移动到一个新位置时,旧位置变为空,所以当它的析构函数被调用时,没有什么可做的。

如果你使用return传递资源,那么你不需要做任何特别的事情,return会自动移动。

例如:

std::unique_ptr<resource> get_resource()
{
    std::unique_ptr<resource> result(new resource());

    if (result->is_something_wrong())
    {
        throw std::exception();
    }

    return result;
}

如果你想将资源传递给一个字段,或者类似的东西,那么你需要明确地说你想通过使用std::move来移动它:

class resource_user
{
    void init_resource()
    {
        std::unique_ptr<resource> result(new resource());

        if (result->is_something_wrong())
        {
            throw std::exception();
        }

        resource_ = std::move(result);
    }

    std::unique_ptr<resource> resource_;
};

【讨论】:

  • Move 应该是默认值,因为它通常比复制更快并且具有不同的含义(原始资源被重用)。此外,对于既不能复制也不能移动的资源还有第三种情况,例如 std::mutex(但这些情况不太常见)。
  • @dyp 我不认为它应该是默认值。当我做a = b 时,我不希望b 变成空的。
  • 我不是这个意思。 OP 具有获取资源并希望将资源取出(返回)的功能。这应该通过默认移动来完成。
猜你喜欢
  • 2010-11-22
  • 1970-01-01
  • 1970-01-01
  • 2017-08-20
  • 1970-01-01
  • 2015-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多