我想做这样的事情

#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;
}

我的问题是:函数参数评估的顺序未指定,因此可以安全地传递将在一个参数中从中移出的值,以及使用实例调用另一个函数的结果,并作为引用传递给- const,作为另一个论点?

我认为问题可以归结为准确执行实际 move 操作的时间,这一点我还不清楚(特别是在打开优化功能时)。

最佳答案

在执行std::unique_ptr<Foo>的move构造函数之前,不会发生实际的“move ”(所有std::move()所做的工作都是将const FooPtr & rvalue强制转换为FooPtr && rvalue引用)。在调用要委派的两个参数Baz构造函数之前,不会发生这种情况。为了使这种情况发生,必须首先评估该构造函数的所有参数。因此,在评估这些参数时对foo对象的任何使用都将发生在unique_ptr实例的实际“move ”之前。

由于您要传递FooPtr(也就是按值传递的std::unique_ptr<Foo>,并且std::unique_ptr是仅 move 的),因此在将两个参数的构造函数的第一个参数赋值时,将触发一个move构造。由于未指定参数的赋值顺序,因此该举或在第二个参数求值之前可能不会发生。因此,示例的行为未指定

关于c++ - 以下代码是否会调用未定义的行为?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27531495/

10-14 16:25