如何将左值转换为右值?以及“新”标签会发生什么

How do you convert a lvalue to an rvalue? And what happens to the `new` lvalue?

本文关键字:标签 什么 转换 以及      更新时间:2023-10-16

我想使用 std::vector::push_back() 将对象移动到std::vector中。 这似乎是可能的,因为有一个std::vector::push_back(value_type&& val)函数。 但是由于存在 std::vector::push_back(value_type const & val) ,它复制并且将是覆盖调用,我需要将左值对象转换为右值。

这是怎么做到的?

例:

struct X { int x; X(int x) : x(x) {} };
int main()
{
    std::vector<X> ax;
    X x(3);
    ax.push_back(x);  // <= Want to move x in to vector ax, not copy.
    return 0;
}

其实,也许不可能? 我问这个是因为写完这个例子后,我的新问题是:

  • 如果我真的把x搬到axx.x的价值是什么? 如果X有一个显式析构函数,那么当x离开范围时会发生什么?

只需使用 std::move()

ax.push_back(std::move(x));

关于您的问题:

如果我确实将 x 移动到 ax 中,x.x 的值是多少?

在这种情况下,您的类X不包含显式声明的 move 构造函数,因此编译器将生成一个对 X 的成员进行成员移动的构造函数。由于X只有一个类型为 int 的成员,并且移动int与复制它没有什么不同,因此x.x将具有与移动之前相同的值。

如果 X 有一个显式析构函数,那么当 x 离开范围时会发生什么?

如果X具有用户声明的析构函数,这将禁止生成隐式移动构造函数 - 但不会禁止生成隐式复制构造函数。因此,此函数调用:

ax.push_back(std::move(x));

将导致x复制到ax 中。在任何情况下,x在超出范围时都会被销毁,因为它具有自动存储持续时间 - 无论是否存在用户声明的析构函数。

一般来说,人们不应该对已移动的对象的状态做出假设,除非该状态是有效的(C++11标准的第17.6.5.15/1段保证了标准库的类型也是如此(。

具体而言,这意味着唯一可以安全地处理已移动对象的函数是那些对该对象的状态没有任何先决条件的函数。通常,两个这样的函数是析构函数和(复制或移动(赋值运算符。