gpt4 book ai didi

c++ - destroy_at/构造不可复制的 vector 元素有多大风险?

转载 作者:行者123 更新时间:2023-12-04 12:27:21 24 4
gpt4 key购买 nike

我已经搜索过 SO 并对以下内容是否安全有疑问。
考虑这个 vector :

std::vector<std::pair<const key, value>> vec;
想象一下,我想交换并弹出位置 i 处的元素。与最后一个。
暂时忽略这样一个事实,即如果出现问题, vector 可能处于不安全状态。我完全知道这一点,但问题更多的是关于周围的其他操作。
由于我无法交换这两个元素,因此我很想这样做:
auto *elem = std::addressof(vec[i]);
std::destroy_at(elem);
std::construct(alloc, elem, std::move(vec.back());
vec.pop_back();
同样,我们在第 2 行和第 3 行之间处于不安全状态,但让我们忽略它。
我很想知道是否销毁和重建位置 i 处的元素对所有人都是安全的 i反而。
根据我的理解,我有几个疑问:
  • i是 0,我们在某种程度上使用与 vector 本身存储的相同的初始指针。因此,我想知道在这种情况下我们是否应该强制 vector 为 std::launder它(是的,这是不可能的,我只是在这里进入理论领域)。
  • 由于这对有一个 const 键,我想破坏和重建它会导致 UB。虽然,我不是 那个确定这一点,只是我的直觉。
  • 最佳答案

    起初,我只是指你的这个问题,看看你对常量成员的关注以及没有 std::vector 上下文的问题。和 std::construct_at ( std::construct 需要分配器进一步...):

    Since the pair has a const key, I guess destroying and recostructing it can lead to UB. Though, I'm not that sure about this, just my gut feeling.


    在 C++20 之前,你是对的,如果旧的引用和指针仍在使用,这将是 UB。但是从 C++20 开始, basic.life#8.3 中有一个相关的变化。到
    n4861/basic.life#8.3

    If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if the original object is transparently replaceable (see below) by the new object. An object o1 is transparently replaceable by an object o2 if

    1. the storage that o2 occupies exactly overlays the storage that o1 occupied, and
    2. o1 and o2 are of the same type (ignoring the top-level cv-qualifiers), and
    3. o1 is not a complete const object, and
    4. neither o1 nor o2 is a potentially-overlapping subobject, and
    5. either o1 and o2 are both complete objects, or o1 and o2 are direct subobjects of objects p1 and p2, respectively, and p1 istransparently replaceable by p2.

    因此,对于这些更改,对于您的特定(!)示例,实际上一般来说应该没问题,因为 vector 元素必须是非常量的,即引用的对象不能是常量完整的(子点 3)。请记住,这些短语与进一步使用旧引用和指向此重用位置的指针的情况相关!在显式销毁(不是取消分配)之后的简单放置 new 是先验的,它是进一步的上下文,与有关 UB 的问题相关。
    另见讨论来自
    Is it possible now with the current C++ standard draft version to define a copy assignment operator for classes with const fields without UB
    服用 std::vector -context 考虑到 std::construct_at除了零位情况:
    您对常量成员的担忧实际上不再与此处相关,因为我们有一个中间层:分配器( std::vector)和简单连续存储的 promise 以及没有对旧的“未决”引用的事实内存(只要您不进一步引用旧的 elem 指针...)。否则,将无法在标准 vector 容器上/内部进行大量高效操作(将数据放入预先分配的范围内)。标准库本身使用类似的移动和插入方案,例如,对于许多容器类型。以这种方式绕过外部容器的内部内存“假设”仍然非常难看,但对于 std::vector 的所有常见实际库实现应该没问题。 (但肯定不适用于具有复杂内部逻辑(如 map )的容器!)。

    关于c++ - destroy_at/构造不可复制的 vector 元素有多大风险?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69756973/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com