代码之家  ›  专栏  ›  技术社区  ›  skypjack

std::launder、std::vector和move仅可构造类型

  •  1
  • skypjack  · 技术社区  · 6 年前

    对于一个 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; };
    

    使用目的 性病:洗脸 是针对可能的优化设置障碍,因为 v 在内部 Mype型 const . 因此能够回收为 vec[i] 为了用不同的实例替换包含的对象(实际上,我在理论上 移动 最后一项到另一个位置)。

    这是一个有效的方法/解决方案,还是仍然是UB,如果我做了类似的事情而没有重复 性病:洗脸 ?

    据我所知, 性病:洗脸 是允许用户做像这样的事情,因此在我看来,上面的代码片段是合法的。但如果我错了,我不会感到惊讶,所以我想得到比我更有经验的人的反馈

    --- 编辑

    同样,我也希望 掉期 到相同类型的元素。
    结果代码应该是这样的:

    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)};
    

    我很有信心如果 性病:洗脸 与第一个例子相吻合,由于类似的原因,这个例子也应该有效。我错了吗?

    1 回复  |  直到 6 年前
        1
  •  4
  •   T.C. Yksisarvinen    6 年前

    launder 获取指向已存在对象的指针。

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

    甚至打电话给 流槽 它本身就是纯粹的无掺杂UB。

    对于这种事情, 流槽 当你 接近 新创建的对象。当你创建它的时候不会。