版权所有 © 2022-2024 Andrey Semashev
根据 Boost 软件许可协议 1.0 版发布。(请参阅随附文件 LICENSE_1_0.txt 或在 https://boost.ac.cn/LICENSE_1_0.txt 复制。)
目录
Boost.Scope 库是一组实用工具的集合,旨在帮助在离开作用域时执行代码以及自动资源管理。该库包含的组件类似于C++ 库基础扩展,版本 3 技术规范(或简称 TS)中,<experimental/scope>
标准库头文件中指定的组件,最初在 P0052R10 中定义。该库还包含对 TS 的扩展,以提高组件的可用性和效率。
该库提供的组件可以分为两类
该库在其命名空间 boost::scope
中定义了其组件。为了简洁起见,本文档中可能会省略命名空间限定;读者应假定未限定的名称(如 scope_exit
或 unique_resource
)在 boost::scope
中定义。
作用域守卫允许用户在离开声明作用域守卫的作用域时执行一段代码(一个动作)。根据作用域守卫的不同,动作可以无条件执行,在正常离开作用域时执行,或者由于异常而执行,甚至可以根据用户指定的条件执行。这在各种用例中都可能很有用,下面将举例说明其中一些用例。
表 1.1。 Boost.Scope 作用域守卫的语法概述
C++11 |
C++17 |
---|---|
class adder { int x, y; public: // Computes a sum of integers int compute() { // Reset variables on return or exception auto cleanup = boost::scope::make_scope_exit([this] { x = 0; y = 0; }); long long int sum = static_cast< long long int >(x) + static_cast< long long int >(y); if (sum < std::numeric_limits< int >::min() || sum > std::numeric_limits< int >::max()) { throw std::overflow_error("Integer overflow"); } return static_cast< int >(sum); } }; |
class adder { int x, y; public: // Computes a sum of integers int compute() { // Reset variables on return or exception. // Anonymous scope guard. BOOST_SCOPE_DEFER [this] { x = 0; y = 0; }; long long int sum = static_cast< long long int >(x) + static_cast< long long int >(y); if (sum < std::numeric_limits< int >::min() || sum > std::numeric_limits< int >::max()) { throw std::overflow_error("Integer overflow"); } return static_cast< int >(sum); } }; |
template< typename Object > class collection { std::set< Object > objects; public: // Adds a new object to the collection Object& add_object() { auto it = objects.emplace(); // Revert object insertion on exception auto cleanup = boost::scope::make_scope_fail([this, it] { objects.erase(it); }); // Throws on error it->on_added(*this); return *it; } }; |
template< typename Object > class collection { std::set< Object > objects; public: // Adds a new object to the collection Object& add_object() { auto it = objects.emplace(); // Revert object insertion on exception boost::scope::scope_fail cleanup{[this, it] { objects.erase(it); }}; // Throws on error it->on_added(*this); return *it; } }; |
// Writes a list of strings to the file, in CSV format bool save_as_csv(std::vector< std::string > const& strings, std::string const& filename) { std::ofstream file(filename.c_str(), std::ios_base::out | std::ios_base::trunc); if (!file.is_open()) return false; // Set a scope guard to remove the partially written file // in case of error - exception or not auto remove_guard = boost::scope::make_scope_exit([&file, &filename] { file.close(); // close the file to allow remove() to succeed on Windows std::remove(filename.c_str()); }); bool first = true; for (auto const& str : strings) { if (!first) file << ','; else first = false; file << '"' << str << '"'; if (file.fail()) return false; } file << std::endl; if (file.fail()) return false; // Commit the operation remove_guard.set_active(false); return true; } |
// Writes a list of strings to the file, in CSV format bool save_as_csv(std::vector< std::string > const& strings, std::string const& filename) { std::ofstream file(filename.c_str(), std::ios_base::out | std::ios_base::trunc); if (!file.is_open()) return false; // Set a scope guard to remove the partially written file // in case of error - exception or not boost::scope::scope_exit remove_guard{[&file, &filename] { file.close(); // close the file to allow remove() to succeed on Windows std::remove(filename.c_str()); }}; bool first = true; for (auto const& str : strings) { if (!first) file << ','; else first = false; file << '"' << str << '"'; if (file.fail()) return false; } file << std::endl; if (file.fail()) return false; // Commit the operation remove_guard.set_active(false); return true; } |
此库提供的作用域守卫与 Boost.ScopeExit 之间存在一些重叠。Boost.ScopeExit 相比,Boost.Scope 提供了更简单的语法(尤其是在支持 C++17 的编译器上)以及针对特定用例的新功能。Boost.Scope 提供的作用域守卫与 Boost.ScopeExit 之间的详细比较在单独的章节中给出。
Boost.Scope 提供的唯一资源包装器是智能指针(如 std::unique_ptr
和 boost::scoped_ptr
,来自 Boost.SmartPtr)的泛化。虽然智能指针适用于管理由指针表示的资源(例如,动态分配内存中的对象),但唯一资源包装器可以用于更多种类的资源类型,例如整数(例如,POSIX 文件描述符)和用户定义的类型。
// Fills the buffer with random bytes from system RNG. Returns 0 on success, otherwise an error code. int get_random_bytes(unsigned char* bytes, std::size_t size) { // Open RNG device and wrap the returned POSIX file descriptor in unique_resource. // This wrapper will automatically close the file descriptor upon destruction by invoking fd_deleter on it. boost::scope::unique_resource< int, boost::scope::fd_deleter, boost::scope::fd_resource_traits > fd(open("/dev/urandom", O_RDONLY)); // fd_resource_traits allows the unique_resource to recognize when open() returns a valid file descriptor // and when it fails and returns -1. In the latter case, the constructed unique_resource is unallocated, // which we test below. if (!fd) return errno; // Read random bytes until the buffer is filled or an error occurs std::size_t read_size = 0u; while (read_size < size) { ssize_t res = read(fd.get(), bytes + read_size, size - read_size); if (res < 0) { int err = errno; if (err == EINTR) continue; return err; } if (res == 0) return ENODATA; read_size += res; } return 0; }