std :: launder,std :: vector并移动仅可构造的类型

时间:2018-12-31 17:26:21

标签: c++ const c++17

对于feature request中的a project of mine ,我认为/建议使用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的目的是为v中的my_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适合第一个示例,则出于类似的原因,该示例也应能正常工作。我错了吗?

1 个答案:

答案 0 :(得分:4)

launder为您提供一个指向已经存在的对象的指针。

那里没有物体。您刚刚在上一行中销毁了它。

即使对launder本身的呼叫也是纯净的UB。

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