将rvalue传递给可能不使用它的函数

时间:2015-11-16 21:22:21

标签: c++ c++11

假设我的课程定义如下:

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值引用但实际上可能不会移动它的参数?

3 个答案:

答案 0 :(得分:3)

如果“某些条件”评估为true,那么add_widget成员函数将在w中移动输入deque之前返回。因此,您可以安全地使用主w

请记住,std::move实际上并不移动对象。 std::move只不过是一个类型转换。

即使移动了w,main中的w也会处于有效但未指定的状态。

这意味着您可以对w执行任何没有先决条件的操作。如果有一个你想要执行前置条件的操作,那么你必须间接执行该操作,因为你不知道对象的未指定状态是否满足前提条件。

LIVE DEMO

答案 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值引用,但如果键尚未存在,它们只会移动到映射中。