对于 feature request的 a project of mine ,我想/有人建议我使用 std::launder
在 vector 中移动元素,其中元素只能移动可构造(未定义移动赋值运算符)。
目标是将最后一个元素移动到给定位置 i
,然后弹出前一个元素。
换句话说,生成的代码将是这样的(为此目的的简化版本):
void foo(std::vector<my_type> &vec, std::size_t i) {
my_type *el = vec.data() + i;
el->~my_type();
new (std::launder(el)) my_type{std::move(vec.back())};
vec.pop_back();
}
my_type
定义为:
struct my_type { const int v; };
使用 std::launder
的目的是为可能的优化设置一个障碍,因为 my_type
中的 v
是常量
。因此,为了能够回收为 vec[i]
保留的内存,以便用不同的实例替换包含的对象(实际上,我理论上移动最后一项到不同的位置)。
这是一个有效的方法/解决方案还是仍然是 UB,因为如果我做了类似的事情而不重复 std::launder
就会发生这种情况?
据我所知,std::launder
的目的是允许用户做这样的事情,因此在我看来上面的代码片段是合法的。但如果我错了我也不会感到惊讶,所以我想得到比我更有经验的人的反馈
--- 编辑
同样,我也想交换到相同类型的元素。
生成的代码应该是这样的:
const auto tmp = std::move(vec[i]);
vec[i].~object_type();
new (std::launder(&vec[i])) object_type{std::move(vec[j])};
vec[j].~object_type();
new (std::launder(&vec[j])) object_type{std::move(tmp)};
我非常有信心,如果 std::launder
适合第一个示例,那么出于类似的原因,这个示例也应该适用。我错了吗?
最佳答案
launder
为您提供指向已存在对象的指针。
那里没有对象。您刚刚在上一行中销毁了它。
甚至调用 launder
本身也是纯粹的 UB。
对于这种事情,当您访问 新创建的对象时,需要launder
。不是在您创建它时。
关于c++ - std::launder、std::vector 和 move 仅可构造类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53989927/