以下代码是否调用未定义的行为
Does the following code invoke undefined behaviour?
我想做这样的事情
#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;
}
我的问题是:函数参数求值的顺序是未指定的,那么传递一个将从一个参数中移动的值,以及调用另一个具有相同实例的函数的结果是否安全,作为对常量的引用传递,作为另一个参数?
我认为问题归结为何时执行实际的移动操作,这一点我不完全清楚(尤其是在启用优化时(。
在
执行 std::unique_ptr<Foo>
的移动构造函数之前,实际的"移动"不会发生(std::move()
所做的只是将const FooPtr &
右值转换为FooPtr &&
右值引用(。在调用要委派到的双参数Baz
构造函数之前,不会发生这种情况。为了实现这一点,必须首先计算该构造函数的所有参数。因此,在评估这些参数时对foo
对象的任何使用都将发生在unique_ptr
实例的实际"移动"之前。
由于您正在传递FooPtr
(也称为按值std::unique_ptr<Foo>
,并且std::unique_ptr
是仅移动的,因此在向双参数构造函数评估第一个参数时,这将触发移动构造。由于未指定参数的求值顺序,因此在计算第二个论点之前可能会也可能不会发生这种移动。因此,您的示例的行为是未指定的。
std::move
不是操作,而是对 r 值引用的强制转换。移动操作将在另一个Baz
构造函数中发生。因此,您正在做的事情应该有效。
Scott Meyers 在他的帖子中提到了一个类似的 SO 问题,仅移动类型是否应该按值传递?似乎没有明确的答案是否应该按值传递它们,但这样做显然会导致未指定的行为,在您的情况下也是如此。
相关文章:
- 从python调用openMP共享库时,未定义opnMP函数
- 尝试调用 .h 文件中定义的变量时出现变量未定义错误
- clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用) - 体系结构的未定义符号 x86_64:
- 调用 Win32 API 函数时未定义的引用
- C++:对函子重载调用运算符的未定义引用
- 在销毁期间从另一个线程调用对象上调用方法是否未定义行为?
- 使用 %s 调用 printf 并传递零长度的字符*是未定义的行为吗?
- 调用提取重加载器会产生对"运算符"的未定义引用错误>>
- 如果用户尝试从 JS 调用对象的未定义函数C++则回调C++代码
- C++:在共享对象中调用抽象基类构造函数/未定义的符号
- 从用户定义的头文件调用函数时出现未定义的引用错误,其实现位于.cpp文件中
- 在 C++ 中调用时对内联程序集代码的未定义引用
- C++调用lua_dostring来加载具有"require('cjson')"的Lua Scrip引发错误:cjson.so:未定义的符号:lua_getfield
- C++程序调用 C 函数 在 g++ 链接期间获取未定义的引用
- 调用函数时未定义标识符"function_name"
- 为什么 std::move 未定义,尽管编译器使用 -std=c++11 调用
- 未定义对调用堆栈库的引用出现问题
- 未定义的对通过静态库中调用的同一文件中定义的函数的引用
- 如何从uint8_t的缓冲区读取带符号整数,而不调用未定义或实现定义的行为
- 已经或将要使用C++14或C++1z使其不再未定义调用委托类成员函数指针