【发布时间】:2020-09-17 11:55:47
【问题描述】:
在某些情况下,我必须添加语句,例如将日志或跟踪添加到表达式中,例如(我想准确记录 prep_stmt.executeQuery() 的时间,但我仍然需要它的返回值):
zdb::PreparedStatement prep_stmt = conn.prepareStatement(sql.data());
prep_stmt.setLLong(1, key);
zdb::ResultSet result = prep_stmt.executeQuery();
// do some stuff with the result
if (result.next()) {
SCOPE_LOG(HANDLE_RESULTS);
auto [data, size] = result.getBlob("v");
// value is a protobuff message
value->ParseFromArray(image, size);
}
假设我想记录prep_stmt.executeQuery() 中的时间。所以我添加了一些这样的宏:
// only for debug
#define EXPR_LOG_BEGIN(Name) \
[&]() { \
SCOPE_LOG(Name); \
return
#define EXPR_LOG_END }();
这里的SCOPE_LOG 是一个使用raii 进行日志记录的宏(愚蠢的SCOPE_EXIT 宏和spdlog):
#define SCOPE_LOG(Expr) \
auto start = chrono::system_clock::now(); \
SCOPE_EXIT { \
auto end = std::chrono::system_clock::now(); \
std::chrono::duration<double, std::milli> elapsed_milliseconds = end - start; \
SPDLOG_LOGGER_INFO(::Logger::getLogger(), \
"[[title={},elapsed_ms={}]]", \
#Expr, elapsed_milliseconds.count()); \
}
并将上面的代码改为:
zdb::PreparedStatement prep_stmt = conn.prepareStatement(sql.data());
prep_stmt.setLLong(1, key);
zdb::ResultSet result =
EXPR_LOG_BEGIN(DB_Execute)
prep_stmt.executeQuery();
EXPR_LOG_END
所以代码展开为:
zdb::PreparedStatement prep_stmt = conn.prepareStatement(sql.data());
prep_stmt.setLLong(1, key);
zdb::ResultSet result = [&]() {
SCOPE_LOG(Name);
return prep_stmt.executeQuery();
}();
这些东西安全吗?使用立即 lambda 为表达式添加语句会是任何隐藏的错误吗?有没有更好的方法来做到这一点?我发现了一个类似的问题:How to immediately invoke a C++ lambda? 但它没有明确说明其用例
【问题讨论】:
-
lambda 有什么用?为什么不简单地
zdb::ResultSet result = prep_stmt.executeQuery(); SCOPE_LOG(Name);或者zdb::ResultSet result = prep_stmt.executeQuery(); { SCOPE_LOG(Name); }?您要解决的实际问题是什么? -
@idclev463035818 我想记录运行
prep_stmt.executeQuery()的时间。当前范围内还有其他一些声明。 SCOPE_LOG 定义一个将在其析构函数中打印日志的对象 -
lambda(temporary) 在通过 () 执行后立即被销毁。所以,关于它的范围(它不会比任何捕获的变量更长寿)它应该是安全的。
标签: c++