首页 > 解决方案 > std::launder、std::vector 和 move 仅可构造类型

问题描述

对于我的项目的功能请求,我认为/我被建议用于在向量中移动元素,其中元素只能移动构造(未定义移动赋值运算符)。 目标是将最后一个元素移动到给定位置,然后弹出前者。std::launder
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是为可能的优化设置障碍,因为vwithinmy_typeconst. 因此能够回收保留的内存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适合第一个示例,那么出于类似原因,这个示例也应该可以正常工作。我错了吗?

标签: c++constantsc++17

解决方案


launder给你一个指向已经存在的对象的指针。

那里没有对象。您刚刚在上一行中将其销毁。

甚至对launder自身的调用也是纯粹的 UB。

对于这种事情,在访问新创建的对象launder时是需要的。不是在您创建它时。


推荐阅读