在某些情况下,“最终"构造将在C ++中有用吗? [英] Are there cases where a "finally" construct would be useful in C++?

查看:94
本文介绍了在某些情况下,“最终"构造将在C ++中有用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Bjarne Stroustrup在他的 C ++样式和技术常见问题解答中写道,重点是我的:

因为C ++支持 几乎总是更好的 :资源获取是初始化"技术(TC ++ PL3第14.4节).基本思想是用本地对象表示资源,以便本地对象的析构函数将释放该资源.这样,程序员就不会忘记释放资源.例如:

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
}

在系统中,每个资源都需要一个资源句柄"类.但是,我们不必为每次获取资源都使用"finally"子句.在现实的系统中,资源获取要比资源种类多得多,因此使用资源获取是初始化"技术所产生的代码要少于使用最终"构造的代码.

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

解决方案

我能想到的是,finally块更好"的唯一原因是,它需要较少的代码来完成同一件事.例如,如果您由于某种原因而没有使用RIIA的资源,则可能需要编写一个类来包装该资源并将其释放到析构函数中,或者使用finally块(如果存在的话)./p>

比较:

class RAII_Wrapper
{
    Resource *resource;

public:
    RAII_Wrapper() : resource(aquire_resource()) {}

    ~RAII_Wrapper() {
        free_resource(resource);
        delete resource;
    }

    Resource *getResource() const {
        return resource;
    }
};

void Process()
{
    RAII_Resource wrapper;
    do_something(wrapper.resource);
}

与之相对:

void Process()
{
    try {
        Resource *resource = aquire_resource();
        do_something(resource);
    }
    finally {
        free_resource(resource);
        delete resource;
    }
}

大多数人(包括我)仍然会认为第一个版本更好,因为它不会强迫您使用try ... finally块.您还只需要编写一次该类,而无需在使用该资源的每个函数中重复该代码.

编辑:就像提到的litb一样,您应该使用auto_ptr而不是手动删除指针,这样可以简化两种情况.

Bjarne Stroustrup writes in his C++ Style and Technique FAQ, emphasis mine:

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.

Note that Bjarne writes "almost always better" and not "always better". Now for my question: What situation would a finally construct be better than using the alternative construct (RAII) in C++?

解决方案

The only reason I can think of that a finally block would be "better" is when it takes less code to accomplish the same thing. For example, if you have a resource that, for some reason doesn't use RIIA, you would either need to write a class to wrap the resource and free it in the destructor, or use a finally block (if it existed).

Compare:

class RAII_Wrapper
{
    Resource *resource;

public:
    RAII_Wrapper() : resource(aquire_resource()) {}

    ~RAII_Wrapper() {
        free_resource(resource);
        delete resource;
    }

    Resource *getResource() const {
        return resource;
    }
};

void Process()
{
    RAII_Resource wrapper;
    do_something(wrapper.resource);
}

versus:

void Process()
{
    try {
        Resource *resource = aquire_resource();
        do_something(resource);
    }
    finally {
        free_resource(resource);
        delete resource;
    }
}

Most people (including me) would still argue that the first version is better, because it doesn't force you to use the try...finally block. You also only need to write the class once, not duplicate the code in every function that uses the resource.

Edit: Like litb mentioned, you should use an auto_ptr instead of deleting the pointers manually, which would simplify both cases.

这篇关于在某些情况下,“最终"构造将在C ++中有用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆