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

C++ 以下代码是否调用未定义的行为?,c++,c++11,move,rvalue,sequence-points,C++,C++11,Move,Rvalue,Sequence Points,我想做这样的事情 #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

我想做这样的事情

#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;
}
#包括
#包括
结构Foo{};
使用FooPtr=std::unique\u ptr;
FooPtr makeFoo(){return FooPtr(new Foo());}
结构Baz
{
Baz(fooptrfoo):Baz(std::move(foo),bar(foo)){}
Baz(fooptrfoo,intsomething):foo{std::move(foo)},something{something}{
私人:
FooPtr_foo;
int_某物;
静态整型条(常量FooPtr&ptr)
{
std::cout在执行
std::unique_ptr
的move构造函数之前,不会发生实际的“移动”(所有
std::move()
都将
const FooPtr&
rvalue转换为
FooPtr&
rvalue引用)。在调用您委派给的双参数
Baz
构造函数之前,不会发生这种情况。为了实现这种情况,必须首先计算该构造函数的所有参数。因此,在计算这些参数时使用
foo
对象将发生在实际“移动”之前属于
唯一\u ptr
实例


因为您正在传递
FooPtr
(a.k.a
std::unique_ptr
by value,and
std::unique_ptr
是move only,在将第一个参数计算到两个参数构造函数时,它将触发move构造。由于参数的计算顺序未指定,因此在计算第二个参数之前可能会发生移动,也可能不会发生移动您的示例的avior未指定。

std::move
不是一个操作,它是对r值引用的转换。move操作将发生在另一个
Baz
构造函数中。因此,您所做的应该是可行的。

Scott Meyers在他的帖子中提到了一个。似乎没有明确的答案它们是否应该按值传递,但这样做显然会导致未指定的行为,在您的情况下也是如此。

如果没有复制省略,第一个参数Baz构造函数会执行移动构造,这可能发生在第二个参数中调用bar之前或之后。因此,结果是未指定的。我认为这是不正确的ect,因为在调用构造函数之前,您必须构造按值传递的参数。为第二个构造函数构造
FooPtr foo
将使
foo
@romal“无效”:是的,我认为您是对的(也请参见galop1n对另一个答案的评论)。证明,反转两个参数会改变结果:(因为clang通常从左到右求值,但这取决于编译器)要清楚的是,调用
bar
是否会看到一个空的参数,并且没有UB,这一点尚不明确。@MattMcNabb:我不太擅长语言律师,但有区别吗?我假设UB有一个严格的定义,但没有涵盖这一点,而我直觉上认为它会被视为这样对待因为未指定参数是否为空。