是否已实现任何 RAII 文件句柄?

问题描述 投票:0回答:3

RAII 文件句柄看起来非常基本,所以我猜它已经被实现了?但我找不到任何实现。我在 boost::iostreams 中找到了 file_descriptor 但我不知道这是否是我要找的。

c++ io raii
3个回答
8
投票

std::fstream
支持 RAII 风格的用法 - 它们可以在构造时打开甚至测试,并且它们会在析构函数中自动刷新和关闭,尽管如果您只是假设它有效,您可能会错过错误,所以您可能想要这样做如果您需要鲁棒性,请在代码中使用更明确的内容。

例如:

if (std::ifstream input(filename))
    ... use input...
else
    std::cerr << "unable to open '" << filename << "'\n";

如果您确实想使用文件描述符,您可以调整如下内容来品尝。它比仅仅调用

close
的东西要长一点,但是如果你想做健壮的编程,你需要以某种方式检查和处理错误......

#include <iostream>
#include <iomanip>
#include <string>
#include <exception>
#include <sstream>
#include <cstring>  // for strerror
#include <unistd.h>  // for close

struct Descriptor
{
    Descriptor(const Descriptor&) = delete;
    Descriptor(Descriptor&&) = default;

    Descriptor(int fd, std::string filename = "")
      : fd_{fd}, filename_{std::move(filename)}
    {
        if (fd < 0)
        {
            std::ostringstream oss;
            throw std::runtime_error(err(oss, "open").str());
        }
    }
    ~Descriptor()
    {
        if (fd_ != -1 && close(fd_) == -1)
            // destructor throw risks termination; avoid
            err(std::cerr, "close") << '\n';
    }
    operator int() const { return fd_; }

  private:
    int fd_;
    std::string filename_;
    
    auto err(auto& os, const char* operation) const -> decltype(os) {
        os << "failed to " << operation << " file";
        if (!filename_.empty())
            os << ' ' << std::quoted(filename_);
        os << ": " << strerror(errno);
        return os;
    }
};


#include <fcntl.h>
int main()
try
{
    const char* filename = "/proc/cmdline";
    Descriptor fd(open(filename, O_RDONLY), filename);
    char buffer[1024];
    std::cout.write(buffer, read(fd, buffer, sizeof buffer)); // TODO error handling
}
catch (const std::exception& e)
{
    std::cerr << e.what() << '\n';
}

7
投票

取决于你到底想要什么。

如果您确实想要一个作用域句柄,请使用:

std::unique_ptr<HANDLETYPE, closehandletypefunction> smartpointer;

对于

FILE
指针,这看起来像

std::unique_ptr<FILE, int (*)(FILE *)> f(fopen("myfile.txt", "a"), fclose);

然后可以用

FILE*
获得
f.get()
。同样的事情也适用于文件描述符(分别来自
open
close
<fcntl.h>
<unistd.h>
)。

首选的 C++ 方法是将句柄包装在具有数千个成员的对象中以完成所有操作。


2
投票

我正在使用

boost::filesystem::ifstream
(或
ofstream
进行书写)。

我实际上问这个问题是因为我想确保即使在调用之前引发异常,我的文件也已关闭

file.close()

但是再次阅读文档后:

如果对象在仍与打开的文件关联时被销毁,则析构函数会自动调用成员函数 close。

所以,这是安全的:)

© www.soinside.com 2019 - 2024. All rights reserved.