以下代码是否调用未定义的行为?

wak*_*jah 8 c++ move rvalue sequence-points c++11

我想做这样的事情

#include <iostream>
#include <memory>

struct Foo {};

using FooPtr = std::unique_ptr<Foo>;

FooPtr makeFoo() { return FooPtr(new Foo()); }

struct Baz
{
    Baz(FooPtr foo) : Baz(std::move(foo), bar(foo)) {}
    Baz(FooPtr foo, int something) : _foo{ std::move(foo) }, _something{ something } {}
private:
    FooPtr _foo;
    int _something;

    static int bar(const FooPtr & ptr)
    {
        std::cout << "bar!" << std::endl;
        return 42;
    }
};

int main() {
    Baz baz(makeFoo());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:函数参数求值的顺序是未指定的,因此传递将从一个参数中移出的值是安全的,并且调用具有相同实例的另一个函数的结果作为reference-to-const传递,作为另一个论点?

我认为这个问题可以归结为实际移动操作何时执行,我不完全清楚(特别是在开启优化时).

Jas*_*n R 9

std::unique_ptr<Foo>执行移动构造函数之前不会发生实际的"移动" (所有std::move()操作都将const FooPtr &rvalue转换为FooPtr &&右值引用).Baz在调用您委派给的双参数构造函数之前,不会发生这种情况.为了使其发生,必须首先评估该构造函数的所有参数.因此,foo在评估这些参数时,对象的任何使用都将在unique_ptr实例的实际"移动"之前发生.

由于你传递了FooPtr(也就是std::unique_ptr<Foo>按值,并且std::unique_ptr只是移动,在评估双参数构造函数的第一个参数时会触发移动构造.由于参数的评估顺序未指定,该移动可能会也可能不会第二个参数的评估之前发生的.因此,你的榜样的行为不确定的.

  • 证明,反转这两个参数会改变结果:http://coliru.stacked-crooked.com/a/37f85e8a5397eec2(因为clang通常从左到右评估,但这依赖于编译器) (4认同)