while(model.condition) {
auto data = yield_data();
auto _= manipulate(model, data);
model.get_info(args);
}
我有一个类型为manipulate
的RAII对象,其析构函数可以消除它超出范围时引起的突变,就像std::lock_guard
一样。问题是用户必须键入auto _=
,否则析构函数将在model.get_info()
之前被调用;我不喜欢用户必须输入auto _=
。用户为什么要考虑创建一个从未使用过的对象?
我的第一个想法是使构造函数[[nodiscard]]
;但是构造函数没有返回值。有没有办法告诉编译器,操纵右值应具有左值生存期?
答案 0 :(得分:2)
对于std::lock_guard
来说,这也是一个未解决的问题,如果您忘记给它起一个名字,就会得到一个错误。
此处有一些技巧:How to avoid C++ anonymous objects
有关此问题和其他陷阱的讨论,请链接到这里:Different behavior when `std::lock_guard<std::mutex>` object has no name
答案 1 :(得分:1)
如果不将rvalue绑定到某个变量,则无法将rvalue的生存期扩展到超出它的完整表达式的范围。因此,不幸的是,您将不得不以某种方式将右值变成左值,或者将实际工作移到不超过右值的范围内。
实现后者的一种方法是使用回调,如此处其他答案所示。
或者,由于有保证的复制省略,您可以将manipulate()
转换为函数,而不必直接调用构造函数。这至少可以让您利用[[nodiscard]]
属性,例如:
[[nodiscard]] manipulate begin_transaction(const Model& model, const Data& data)
{
return { model, data };
}
while(model.condition)
{
auto data = yield_data();
auto guard = begin_transaction(model, data);
model.get_info(args);
}
答案 2 :(得分:0)
您必须执行此操作。没有其他选择。
NAG自动微分DCO库就是一个令人痛苦的好例子,您必须在其中向代码添加大量const auto&
,因为它们依靠破坏顺序来创建图形(RAII,就像您一样依靠这个。)
可以这样说,甚至使用const auto& _
,以确保在需要时不会更改_
。
答案 3 :(得分:0)
要求用户告诉manipulate
ctor他们想运行什么代码。因此,将其更改为以callable作为参数并调用它:
manipulate(model, data, [&model, &args] {
model.get_info(args);
});