移动语义和参数评估顺序

Tom*_*Tom 25 c++ operator-precedence move-semantics c++11

考虑以下因素:

std::string make_what_string( const std::string &id );

struct basic_foo
{
    basic_foo( std::string message, std::string id );
};

struct foo
    : public basic_foo
{
    foo::foo( std::string id)
        : basic_foo( make_what_string( id ), std::move( id ) ) // Is this valid?
    {
    }
};
Run Code Online (Sandbox Code Playgroud)

因为C++中的参数评估顺序是未指定的,所以我想知道是否该行

basic_foo( make_what_string( id ), std::move( id ) )
Run Code Online (Sandbox Code Playgroud)

在上面的代码是有效的.

我知道这std::move只不过是一个演员,但什么时候执行std :: string move ctor?在评估完所有参数之后,是否应该调用基础构造函数?或者这是在评估参数期间完成的?换一种说法:

编译器是否这样做:

std::string &&tmp2 = std::move(id);
std::string tmp1 = make_what_string(id);
basic_foo(tmp1, tmp2);
Run Code Online (Sandbox Code Playgroud)

这是有效的.或这个:

std::string tmp2 = std::move(id);
std::string tmp1 = make_what_string(id);
basic_foo(tmp1, tmp2);
Run Code Online (Sandbox Code Playgroud)

这是无效的.请注意,在这两种情况下,订单都是"意外"订单.

Jos*_*eld 17

见1.9节:

除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的.

当调用函数时(无论函数是否为内联函数),与任何参数表达式相关联的每个值计算和副作用,或者使用指定被调用函数的后缀表达式,都会在执行每个表达式或语句之前对其进行排序.叫功能.[ 注意:与不同参数表达式相关的值计算和副作用未被排序.- 结束说明 ]

我认为问题在于,参数的初始化是否被认为是与参数表达式相关的副作用还不是很清楚.但是,它似乎得到第5.2.2节的支持:

每个参数的初始化和销毁​​发生在调用函数的上下文中.

并且在同一段中还有一个注释使它更清晰:

调用函数时,应使用相应的参数初始化每个参数(8.3.5)(8.5,12.8,12.1).[ 注意:这种初始化相对于彼此不确定地排序(1.9) - 结束注释 ]

所以,是的,参数的初始化是相对于彼此不确定地排序的.初始化可能发生在以下任一订单中:

std::string message = make_what_string(id);
std::string id = std::move( id );

std::string id = std::move( id );
std::string message = make_what_string(id);
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,make_what_string最终使用移动的字符串.

因此,即使std::move实际上并没有移动任何东西,重要的是实际移动对于另一个论点也没有后果.

移动构造函数的定义basic_string(basic_string&& str):

[...] str保留在具有未指定值的有效状态.

因此,您没有未定义的行为,您有未指定的行为.


Rei*_*ica 7

这不是真的有效.函数参数评估的顺序未指定.换句话说,您不知道编译器是否会选择此序列:

tmp1 = make_what_string(id);
tmp2 = std::move(id);
basic_foo(tmp1, tmp2);
Run Code Online (Sandbox Code Playgroud)

或者这个:

tmp1 = std::move(id);
tmp2 = make_what_string(id);  //id has already been moved from!
basic_foo(tmp2, tmp1);
Run Code Online (Sandbox Code Playgroud)

  • 问题是参数评估是否包括参数的初始化. (5认同)