假设我的课程定义如下:
class Foo {
public:
...
bool add_widget(Widget&& w) {
if (some condition) {
return false;
}
container.push_back(std::move(w));
return true;
}
private:
std::deque<Widget> container;
}
我将课程称为如下:
int main(int argc, char* argv[]) {
Foo f;
Widget w;
if (!f.add_widget(std::move(w))) {
// Can I still use w here?
}
}
如果some condition
为真,则小部件w
将不会添加到Foo的container
。在main()
中,当add_widget()
返回表明添加不成功时,我仍然可以使用w
,还是应该始终认为它已被移动且不再可用?
编写像add_widget()
这样的函数是不好的做法,它采用r值引用但实际上可能不会移动它的参数?
答案 0 :(得分:3)
如果“某些条件”评估为true
,那么add_widget
成员函数将在w
中移动输入deque
之前返回。因此,您可以安全地使用主w
。
请记住,std::move
实际上并不移动对象。 std::move
只不过是一个类型转换。
即使移动了w
,main中的w
也会处于有效但未指定的状态。
这意味着您可以对w
执行任何没有先决条件的操作。如果有一个你想要执行前置条件的操作,那么你必须间接执行该操作,因为你不知道对象的未指定状态是否满足前提条件。
答案 1 :(得分:1)
在这种情况下使用widget非常好,因为它的状态不会以任何方式改变。
但是,您应该只依赖于此行为,如果您在函数描述中明确地记录它,并且因此 - 即使在将来重构的情况下也愿意承诺该保证。
有人可能会争论,这是否过于聪明和/或令人惊讶,但事实上它与依赖std::vector::push_back()
等功能的强大异常保证并没有太大区别。
答案 2 :(得分:0)
这个习惯用法从c ++ 17开始在标准库中使用。
查看std::map::try_emplace
参考:http://en.cppreference.com/w/cpp/container/map/try_emplace
请注意,键类型(实际上在某些情况下,用于构造值的参数)是r值引用,但如果键尚未存在,它们只会移动到映射中。