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

标签 c++ constants c++17

对于 feature requesta 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/

相关文章:

c++ - 在 switch 语句中使用常量数组的元素作为 case

c++ - 强制列表初始化矩阵的大小

c++ - 使用 boost 格式化负数

C++ 自定义容器传递 {} 列表

c - 在 C 中声明常量字符串的最佳方法

swift - switch 语句中的常量绑定(bind)实际上有什么作用?

c++ - 是否可以将类的对象转换为 void *?

c++ - 这行C代码是什么意思?

c++ - 在 C++17 中使用转发引用时,模板结构是否需要 std::decay?

c++ - 使用 invoke_result 的正确方法?