【问题标题】:Can you truncate std::vector<int> in constant time?你能在恒定时间内截断 std::vector<int> 吗?
【发布时间】:2022-12-14 12:55:22
【问题描述】:

有几种方法可以使向量为空,包括

std::vector<int> example = makeMyReallyBigVector();
example.clear();
example.resize(0);
example.erase(example::being(), example::end());
// any other method which would be relevant

C++ 标准中是否有关于哪个最有效、时间最明智的保证?内容是没有析构函数的原始数据类型。我特别关心的是,我不希望向量容量发生变化,我只希望它的内部“已用大小”设置为 0,而不触及现在已删除的内容。

我想要的是在恒定时间内将 int 向量大小设置为 0,而不释放任何内存。这在 C++ 标准中可行吗?

如果 C++ 标准不提供任何保证,我正在使用 GNU C++ 标准库,那么如果标准不提供任何保证,那是否提供任何保证?为了便于移植,在这种情况下,当然也会对有关 Clang 和 Microsoft 标准库的信息感兴趣。

【问题讨论】:

  • 在您的情况下,所有这三种方法最终都会做同样的事情,因此请使用您想要的任何一种。
  • 您可以随时检查生成的机器代码。例如,在这个现场演示中,这三种情况几乎相同:godbolt.org/z/c6r4haofY
  • @LouisGo 理论上是的。实际上,如果值类型的销毁操作实际上是空操作,那么它可以优化为 O(1) 机器代码。
  • @hyde——好点。这就是为什么我强调永远不要编写一个空的析构函数,而只是将其省略或声明它=default。编写一个空的析构函数会改变类的特征,如果存储在向量中的类型的特征不是平凡可破坏的,那么您所说的优化可能不会发生。
  • @Raildex 调整大小不会减少容量。

标签: c++ stdvector


【解决方案1】:
example.clear();

clear 是:

与容器的大小成线性关系,即元素的数量。

example.resize(0);

resize

当前大小和计数之间的差异呈线性。如果容量小于计数,则重新分配可能会导致额外的复杂性

example.erase(example::begin(), example::end());

erase

线性:调用T的析构函数的次数与被擦除的元素个数相同,T的赋值运算符被调用的次数等于vector中被擦除元素之后的元素个数

我不确定为什么 clearresize 都没有提到对析构函数的依赖。 int 只有一个伪析构函数(使对 int 有效调用析构函数的东西,但它不执行任何操作)。

如果元素确实具有析构函数,则复杂性是线性的。对于int,编译器可能足够聪明,可以在恒定时间内完成。当您不确定运行时间时,唯一可以确定的方法就是测量。

【讨论】:

    【解决方案2】:

    example.clear(); 可能会更快。上述所有示例都带有参数,这意味着将生成额外的代码以将它们传递给需要执行的函数。

    但是,重要的是要记住 C++ 编译器非常聪明,可能能够将 example.resize(0); 转换为 example.clear();。但事实并非如此。因此,如果不困难,最好帮助编译器。

    【讨论】:

    • 请注意:我在问题中添加了一段以阐明我想要实现的目标。
    • 大多数 STL 代码都是内联的,因此传递参数不会生成更多代码(即使关闭了优化)。我建议使用clear(),因为它更明确地说明了你在做什么。
    • @hyde,通常,STL 中没有我们想要的那么多保证。如果您需要一个保证完全按照您想要的方式工作的容器,请编写您自己的容器。这一点都不难,事实上,例如,当涉及到 int 时,并不难。我建议通过 cstdlibmalloc 进行此操作。
    • @AlexA。如果你问我,编写自己的容器几乎不是一个好主意,除非是作为学习练习.如果标准容器真的不行,还有其他经过良好测试的库可以使用。我强烈反对在现代 C++ 代码中使用 malloc,或者实际上是裸露的 new。只需在需要使用裸露的new(或malloc)的任何地方使用std::make_unique
    • @hyde,如果你想要一个真正保证有效的代码,你有时必须在C++中使用C。 new 没有调整大小的能力,但是 malloc 有:realloc。 C++ 编译器确实可以进行非常复杂的优化,但不是全部。要确切地知道编译器在什么情况下以及在什么情况下可以保证改进,您需要非常了解每个编译器中的优化列表及其在每种情况下的适用性。可以肯定的是,您需要查看编译器输出的反汇编代码。
    猜你喜欢
    • 1970-01-01
    • 2020-01-26
    • 2021-08-18
    • 2017-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    相关资源
    最近更新 更多