c++ - 回调的这种用法是惯用的吗?
问题描述
我注意到我的一些代码中有一个共同的模式
std::string line;
if (!in || !std::getline(in, line)) {
throw line_read_error(in,line_counter);
}
++line_counter;
std::istringstream sin{line};
// ...read from sin...
if (!sin.eof()) {
sin.clear();
throw incomplete_read_error(in,line_counter,sin.tellg());j
}
我从该行读取的内容在每个位置都不同,但设置和读取后检查是相同的。
我把它分解出来,创建一个对象来保存我的in
流和line_counter
,并为主体传递一个回调:
class LineReader {
std::istream& in;
size_t line_counter;
public:
template <typename Function>
void with_next_line(Function callback) {
std::string line;
if (!in || !std::getline(in, line)) {
throw line_read_error(in,line_counter);
}
++line_counter;
std::istringstream sin{line};
callback(sin);
if (!sin.eof()) {
sin.clear();
throw incomplete_read_error(in,line_counter,sin.tellg());j
}
}
// ...
}
将我的用途更改为
line_reader.with_next_line([/*...*/](auto& sin){
// ...read from sin...
});
这肯定是少了重复,但还是有点尴尬。
然而,我真正关心的是其他人是否容易理解,因为我真的在努力使我的代码尽可能清晰。
像这样的东西我会更好吗
auto sin = line_reader.get_next_line();
// ...read from sin...
line_reader.check_done(std::move(sin));
解决方案
进行设置 + 清理 的正常方法是拥有一个对象,其构造函数执行设置,析构函数执行清理 (RAII)。
但是,如果您还没有读到最后,您想要做的清理就是抛出 - 从析构函数中抛出是邪恶的、坏的和错误的。这意味着在这种特殊情况下您不能使用 RAII。
如果进行检查真的很重要,那么您拥有的代码将强制执行它。如果这只是“一个好主意”,那么我认为这两个调用(之前和之后)可能比 lambda 稍微干净一些。(我不会打扰std::move(sin)
- 使用移动并不会在这里添加任何东西。)
推荐阅读
- git - 从 github.com 删除或重置贡献者?
- javascript - 我如何在公共域上部署 node.js 服务器?
- javascript - 调用具有不同参数的函数并等待第一次执行完成
- javascript - 如何在函数中使用属性
- php - 用于远程 jpg 的 phpOffice/phpWord php is_file() 总是错误的
- javascript - 在前端或后端保留过滤逻辑
- python - 即使我填写了所有必需的参数,为什么我的 django 表单无效?
- javascript - 在打字稿中删除 JSON 对象数组中的属性
- haskell - 我无法在 Haskell 中运行模块
- python - spark中的迭代过滤器似乎不起作用