是否有任何未定义的行为问题,当移动数据到一个函数,然后回到它来自哪里

Are there any undefined behavior issues when moving data into a function and then back out to where it came from?

本文关键字:函数 然后 一个 未定义 问题 是否 数据 移动 任何      更新时间:2023-10-16

考虑以下函数:

std::vector<int> pushIt(std::vector<int> v){
    v.push_back(10);
    return v; 
}
int main(){
    std::vector<int> vec;
    vec = pushIt(std::move(vec));
}

我的假设是向量被移动到函数中,修改并移动到它原来的位置。这将导致类似于将其作为非const引用传递的行为。这似乎是相当有效的行为,但同事害怕未定义的行为。我还遗漏了什么吗?

我想这样做是因为当前函数

void currentPushIt(std::vector<int>& v){
    v.push_back(10);
}

在代码审查中导致了很多问题,因为人们忽略了一个事实,即对currentPushIt(v)的无害调用可能会使迭代器无效。让他们写v=pushIt(std::move(v))应该足以唤醒他们,使他们不再犯同样的错误。

在1.9p15中,与实参相关的值计算和副作用在执行函数体之前进行排序。所以当你输入pushIt时,源vec已经被移走了。然后在执行pushIt之后对赋值进行排序,因为实际上调用的是用户定义的操作符vector::operator=:

vec.operator=(       // sequenced after
    pushIt(          // the evaluation of this, which is sequenced after
        std::move(   // the evaluation of this
            vec)))

所以你的代码没问题

您的同事担心是没有理由的,所显示的代码片段没有未定义行为


所写的代码片段,由于std::vector是一个类,因此相当于下面的代码,并且由于函数形参在调用函数之前必须有一个值,因此相当于先调用std::move,然后调用pushIt,最后调用vec.operator=

从这种角度来看,很明显,编写这样的代码实际上是安全的。

vec.operator= (pushIt (std::move (vec));

一般

a = do_something (a);

我遇到过开发人员担心这样的代码片段,因为=不是序列点;如果do_something修改了a,左边会发生什么?

长话短说;没关系。尽管我们不知道左边和右边的求值顺序,但它在正确性方面是定义好的。


=的左边是一个左值,这可以看作是某个值最终的位置。无论存储在该位置的值是什么,实际位置都是相同的。

在这种情况下,右边将从vec移动。这无疑会改变vec的值,但不会改变vec所在的位置;因此,右边的结果将被正确地赋值到它应该赋值的位置。

注意:实际赋值是排序的,lhsrhs都必须在赋值前求值(即:在rhs的值由lhs分配给位置yield之前,但是lhsrhs的求值顺序并不是固定的。

是否有任何未定义的行为问题移动数据到函数,然后回到它来的地方?

函数参数在函数求值之前"顺序"求值。赋值在右侧求值之后"排序"。

相关文章: