【问题标题】:Does std::vector::assign/std::vector::operator=(const&) guarantee to reuse the buffer in `this`?std::vector::assign/std::vector::operator=(const&) 是否保证重用 `this` 中的缓冲区?
【发布时间】:2018-08-17 09:30:44
【问题描述】:

如果我将一个向量分配或复制到另一个向量(其容量与前者的大小相同或更大),我可以假设后者的缓冲区将被重用吗?

下面的例子表明我可以,但是,它是由标准保证的吗? 在这方面std::vector::assignstd::vector::operator= 的行为有什么区别吗?

#include <vector>
#include <iostream>
#include <cassert>

int main()
{
    std::vector a {1, 2, 3, 4, 5};
    std::vector b {1, 2, 3, 4};
    std::vector c {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::cout << "1 ==== " << a.capacity() << " " << a.data() << std::endl;

    const auto* pa = a.data();   
    a = b;
    assert(pa == a.data());
    std::cout << "2 ==== " << a.capacity() << " " << a.data() << std::endl;

    a = c;
    assert(pa != a.data());
    std::cout << "3 ==== " << a.capacity() << " " << a.data() << std::endl;
}

Live example.

更新This answer 提到

void assign(size_type n, const T& t);

等价于

erase(begin(), end());
insert(begin(), n, t);

标准真的是这样制定的吗?它是否适用于std::vector::assign的所有重载?

【问题讨论】:

  • 通常是的,但它实际上取决于分配器的兼容性和分配器的传播:如果分配器没有在分配时传播,或者源分配器可以释放目标分配器的内存,那么目标缓冲区被重用( target => 赋值运算符右侧,source=> 赋值运算符左侧)。
  • 抱歉,我在最新草稿中找不到与“提到的这个答案”相关的任何内容。标准(据我所知)只说“用 t 的 n 个副本替换 a 中的元素。无效...”参见 [eel.is/c++draft/…
  • 或许可以用vector::reserve()上的要求来证明这一点。类似于:在赋值之前插入一个a.reserve(a.size());,并且赋值可能会受到reserve() 的约束以使用相同的存储(例如,a[0] 的迭代器保证保持有效)。 v.reserve(v.size()); 显然是一个空操作,并且始终适用于一个向量,。但我现在没有时间跟踪标准参考。
  • 另请注意,如果分配器不在复制构造上传播,则原始缓冲区已经(保证)将被释放
  • @L.F.那么assignoperator= 好,不是吗?

标签: c++ c++14 language-lawyer c++17


【解决方案1】:

简答

没有。

不是那么简短的回答

标准没有在vector 上手动定义这些操作。它仅将它们定义为容器的要求。 [vector]

向量满足容器和可逆容器(在 [container.requirements] 中的两个表中给出)、序列容器的所有要求,包括大多数可选的序列容器要求([sequence.reqmts] ),分配器感知容器(表 67),以及对于 bool 以外的元素类型,连续容器。例外是未提供的 push_front、pop_front 和 emplace_front 成员函数。此处仅针对这些表之一中未描述的向量操作或存在附加语义信息的操作提供描述。

唯一提到这些操作的地方是Container requirementsSequence container requirements。没有任何东西支持你的假设。

【讨论】:

  • 至少这是一个实现质量的问题。在所有实现中,最好的办法是减少内存分配的数量,因为它很昂贵。
  • 如果我理解正确,OP 正在寻找标准保证:P 这与实现不完全相同
  • 取决于您在哪里工作。标准是理论,执行是现实。如果您正在制作学生作品,则可以使用该标准。但是,如果您正在编写心脏起搏器的代码,您的分析将基于库的实现,那么心脏就是真实的东西!
  • 在这种特殊情况下,我们是语言律师;请看标签
  • @Oliv - 是的,我意识到你试图说明一个抽象。你选择了一个糟糕的例子。但是感谢您证明您实际上并不了解与安全相关的开发需要什么。如果在安全案例中使用测试来证明声明的合理性,通常需要单独证明测试确实提供了满足测试要求的适当级别的证据的声明。这不仅仅是因为认知偏见而信任系统过程而不是替代方案的情况。
猜你喜欢
  • 1970-01-01
  • 2021-06-02
  • 2023-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
相关资源
最近更新 更多