有没有办法防止 C++ 编译器将临时右值的副本优化为移动操作?

Is there a way of preventing a C++ compiler from optimizing a copy of a temporary rvalue into a move operation?

提问人:metamorphosis 提问时间:4/21/2023 更新时间:4/21/2023 访问量:107

问:

例如:

std::vector<int> i;
i = std::vector{5, 4, 3, 2, 1}

在上述情况下,编译器通常会将第二行优化为移动操作而不是复制操作,尽管缺少 std::move() 外壳。这通常没问题,但在某些情况下可能会导致问题,例如,如果使用特定分配器声明,则目标分配器所发生情况的语义非常不同,具体取决于操作是复制还是移动(如果矢量实现符合标准)。 让我们忽略上面是坏代码,即。它应该是一条线,没有不必要的辅助向量构造,并专注于另一个问题。i

我们可以假设其他用例,在这些用例中,移动旨在对容器元数据执行略微不同的操作。假设我们有一个结构:

struct t
{
   int data;
   int usage;

   // Methods and constructors etc go here
};

该变量告诉我们给定方法访问了多少次。从语义上讲,复制操作可能只是将变量从一个结构实例复制到另一个结构实例。移动操作也希望替换变量,因为它有效地将一个结构实例的整个状态移动到另一个结构实例。忽略你是否认为这不太可能,这只是一个假设的例子,用于说明目的。usagedatadatausage

现在,如果有人写了一些糟糕的代码,例如:

t a;
// Some accesses of a's data member occur here via a member function.

t b = 4;
a = b;
// b is not used after this point.

编译器可以将 b 优化为临时操作,并优化为移动操作。如前所述,这可能会导致问题。a = b

所以。 有没有办法 - 从结构的编写者方面 - 编写方法,以便复制赋值和移动赋值都是可能的,但 C++ 编译器无法将复制操作优化为移动操作 - 即使使用了临时右值?我知道代码的作者可以使用 来防止这种情况,但我对这种特殊情况下的万无一失代码感兴趣。operator =t

谢谢-

C++ 优化 move rvalue 临时

评论

3赞 Miles Budnek 4/21/2023
“编译器可以将 b 优化为临时操作,并将 a = b 优化为移动操作。如前所述,这可能会导致问题。不,它可能不是。 是一个左值。这里不允许进行此类优化。b
0赞 Ted Lyngmo 4/21/2023
有帮助吗?(无省略构造函数部分只是为了好衡量)-std=c++98 -fno-elide-constructors -pedantic
3赞 user2357112 4/21/2023
这个问题的某些部分听起来像是你误解了什么。 实际上只是一个对价值引用的转换。这并不意味着“使用移动构造函数/移动赋值运算符”。当您这样做时,编译器不会将副本优化为移动;它正在选择一个移动,因为这就是 C++ 重载解析规则所说的应该解决的问题。std::movestd::movei = std::vector{5, 4, 3, 2, 1}
0赞 doug 4/21/2023
我强烈建议您查看如何使用 rvalues,例如 xvalues 和 prvalues,尤其是转发引用。cppcon 的 youtube 频道上有一些不错的视频。它可以,而且经常显然是令人困惑的,但是一旦你明白了事情是什么以及为什么会这样,你将来就不会有任何问题了。std::movestd::forward
0赞 metamorphosis 4/23/2023
@user2357112 谢谢你,我不知道。不幸的是,这些陷阱存在于 c++ 中

答: 暂无答案