对于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
中的v
是my_type
,因此使用const
的目的是为可能的优化设置障碍。因此,为了能够回收为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
。创建时不行。