c++ - 是否存在 "finally"构造在 C++ 中有用的情况?

标签 c++ raii finally

Bjarne Stroustrup 在他的 C++ Style and Technique FAQ 中写道,强调我的:

Because C++ supports an alternative that is almost always better: The "resource acquisition is initialization" technique (TC++PL3 section 14.4). The basic idea is to represent a resource by a local object, so that the local object's destructor will release the resource. That way, the programmer cannot forget to release the resource. For example:

class File_handle {
    FILE* p;
public:
    File_handle(const char* n, const char* a)
        { p = fopen(n,a); if (p==0) throw Open_error(errno); }
    File_handle(FILE* pp)
        { p = pp; if (p==0) throw Open_error(errno); }

    ~File_handle() { fclose(p); }

    operator FILE*() { return p; }

    // ...
};

void f(const char* fn)
{
    File_handle f(fn,"rw"); // open fn for reading and writing
    // use file through f
}

In a system, we need a "resource handle" class for each resource. However, we don't have to have an "finally" clause for each acquisition of a resource. In realistic systems, there are far more resource acquisitions than kinds of resources, so the "resource acquisition is initialization" technique leads to less code than use of a "finally" construct.

请注意,Bjarne 写的是“几乎总是更好”而不是“总是更好”。现在我的问题是:什么情况下 finally 构造比在 C++ 中使用替代构造 (RAII) 更好?

最佳答案

它们之间的区别在于,析构函数通过将清理解决方案与正在使用的类型相关联来强调清理解决方案的重用,而 try/finally 强调一次性清理例程。因此,当您有与使用点相关的独特的一次性清理要求,而不是与您正在使用的类型相关联的可重复使用的清理解决方案时,try/finally 会更加方便。

我还没有尝试过这个(几个月没有下载最近的 gcc),但这应该是真的:通过向语言添加 lambda,C++ 现在可以有效地等效于 finally,只需编写一个名为 try_finally 的函数。明显的用法:

try_finally([]
{
    // attempt to do things in here, perhaps throwing...
},
[]
{
    // this always runs, even if the above block throws...
}

当然,您必须编写 try_finally,但只需编写一次,然后就可以开始了。 Lambda 启用新的控制结构。

类似于:

template <class TTry, class TFinally>
void try_finally(const TTry &tr, const TFinally &fi)
{
    try
    {
        tr();
    }
    catch (...)
    {
        fi();
        throw;
    }

    fi();
}

并且 GC 的存在与偏好 try/finally 而不是析构函数之间根本没有联系。 C++/CLI 有析构函数和 GC。它们是正交选择。 Try/finally 和析构函数是针对同一问题的略有不同的解决方案,它们都是确定性的,是不可替代资源所需的。

C++ 函数对象强调可重用性,但使一次性匿名函数变得痛苦。通过添加 lambda,现在可以轻松创建匿名代码块,这避免了 C++ 传统上强调通过命名类型表达的“强制可重用性”。

关于c++ - 是否存在 "finally"构造在 C++ 中有用的情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/385039/

相关文章:

c++ - uintptr_t 与 DWORD_PTR 的用法

c++ - 我如何在 cout/c++ 中写这个?

c++ - 在 Visual Studio 中启用单个警告

rust - 有没有办法在 RwLock drop 上运行闭包?

C# 最终执行时间

c++ - 如何防止 C++ 名称反修饰函数包含在二进制文件中

c++ - 通用句柄类

c++ - 句柄的 Win API 包装器类

java - Java中如何记录被finally block 异常屏蔽的异常?

c++ - 终止 worker