#include <fcntl.h>
#include <unistd.h>

#include <iostream>
#include <stdexcept>

// 不用 RAII：每条退出路径都要记得 close
void withoutRaii(bool fail) {
    int fd = ::open("/etc/hostname", O_RDONLY);
    std::cout << "opened fd " << fd << std::endl;
    if (fail) {
        throw std::runtime_error("something went wrong");  // 忘了 close，fd 泄漏
    }
    ::close(fd);
    std::cout << "closed fd " << fd << std::endl;
}

// 用 RAII：构造时拿到 fd，析构时一定 close
class File {
public:
    explicit File(const char* path) : fd_(::open(path, O_RDONLY)) {
        std::cout << "File opened fd " << fd_ << std::endl;
    }
    ~File() {
        if (fd_ >= 0) ::close(fd_);
        std::cout << "File closed fd " << fd_ << std::endl;
    }
    File(const File&) = delete;             // 禁止拷贝：否则两个对象会 close 同一个 fd
    File& operator=(const File&) = delete;
    int fd() const { return fd_; }

private:
    int fd_;
};

void withRaii(bool fail) {
    File f("/etc/hostname");
    if (fail) {
        throw std::runtime_error("something went wrong");  // f 的析构函数照样会执行
    }
    std::cout << "using fd " << f.fd() << std::endl;
}  // 离开作用域，f 析构

int main() {
    try { withoutRaii(true); } catch (const std::exception& e) { std::cout << "caught: " << e.what() << std::endl; }
    try { withRaii(true); } catch (const std::exception& e) { std::cout << "caught: " << e.what() << std::endl; }
    withRaii(false);
    return 0;
}
