gpt4 book ai didi

c++ - vector::push_back 用于预定义的构造函数?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:50:09 25 4
gpt4 key购买 nike

我在这里问我的看法是否真的正确。我本来想定义 vector<T> v(size_t someSize, T init_value)会调用类似 vector<T>::reserve 的函数, 而不是 vector<T>::push_back .我在这里找到了一些与此相关的讨论:std::vector push_back is bottleneck , 但它的想法略有不同。

运行一些实验,我注意到 vector<T> v(size_t someSize, T init_value)电话 ::push_back一直。这是真的?我使用 uftrace 得到以下报告(https://github.com/namhyung/uftrace)。

     Avg total   Min total   Max total  Function
========== ========== ========== ====================================
858.323 ms 858.323 ms 858.323 ms main
618.245 ms 618.245 ms 618.245 ms sortKaway
234.795 ms 234.795 ms 234.795 ms std::sort
72.752 us 72.752 us 72.752 us std::vector::_M_fill_initialize
65.788 us 49.551 us 82.026 us std::vector::vector
20.292 us 11.387 us 68.629 us std::vector::_M_emplace_back_aux
18.722 us 17.263 us 20.181 us std::equal
18.472 us 18.472 us 18.472 us std::vector::~vector
17.891 us 10.002 us 102.079 us std::vector::push_back // push_back?!

是否 vector<T>::reserve也可以调用vector<t>::push_back最终? vector 有更快的版本吗? ?


以上为原文。经过一些评论,我测试了一个简单的版本,并意识到我完全错了。

#include <vector>
#include <functional>
#include <queue>
#include <cassert>
using namespace std; // for the time being

int main () {
vector<int> v(10, 0);

return 0;
}

这实际上导致以下结果,不涉及 std::vector<T>::push_back .

  # Function Call Graph for 'main' (session: 9ce7f6bb33885ff7)
=============== BACKTRACE ===============
backtrace #0: hit 1, time 12.710 us
[0] main (0x4009c6)

========== FUNCTION CALL GRAPH ==========
12.710 us : (1) main
0.591 us : +-(1) std::allocator::allocator
0.096 us : | (1) __gnu_cxx::new_allocator::new_allocator
: |
6.880 us : +-(1) std::vector::vector
4.338 us : | +-(1) std::_Vector_base::_Vector_base
0.680 us : | | +-(1) std::_Vector_base::_Vector_impl::_Vector_impl
0.445 us : | | | (1) std::allocator::allocator
0.095 us : | | | (1) __gnu_cxx::new_allocator::new_allocator
: | | |
3.294 us : | | +-(1) std::_Vector_base::_M_create_storage
3.073 us : | | (1) std::_Vector_base::_M_allocate
2.849 us : | | (1) std::allocator_traits::allocate
2.623 us : | | (1) __gnu_cxx::new_allocator::allocate
0.095 us : | | +-(1) __gnu_cxx::new_allocator::max_size
: | | |
1.867 us : | | +-(1) operator new
: | |
2.183 us : | +-(1) std::vector::_M_fill_initialize
0.095 us : | +-(1) std::_Vector_base::_M_get_Tp_allocator
: | |
1.660 us : | +-(1) std::__uninitialized_fill_n_a
1.441 us : | (1) std::uninitialized_fill_n
1.215 us : | (1) std::__uninitialized_fill_n::__uninit_fill_n
0.988 us : | (1) std::fill_n
0.445 us : | +-(1) std::__niter_base
0.096 us : | | (1) std::_Iter_base::_S_base
: | |
0.133 us : | +-(1) std::__fill_n_a

抱歉造成混淆。是的,库实现如我们预期的那样工作,它不涉及 push_back如果用 initial size 构建.

最佳答案

呸,看来你回答了你自己的问题!一时之间,我无比的迷茫。只是假设,我可以想象一些晦涩的案例 vector's使用 reserve 填充构造函数和 push_backs ,但绝对不是像 GNU 标准库中伴随 GCC 那样的高质量实现。我想说,假设地,一个晦涩的 vector 实现有可能以这种方式实现,但实际上完全不可能用于任何体面的实现。

相反,这是将近二十年前的事了,但我尝试实现我的 std::vector 版本希望与其性能相匹配。这不仅仅是一些愚蠢的练习,而是由于我们有一个软件开发工具包并想为其使用一些基本的 C++ 容器这一事实而产生的诱惑,但它的目标是允许人们使用不同的方式为我们的软件编写插件编译器(以及不同的标准库实现)与我们使用的不同。所以我们不能安全地使用 std::vector在这些情况下,因为我们的版本可能与插件作者的不匹配。我们被迫不情愿地为 SDK 推出我们自己的容器。

相反,我找到了 std::vector以难以匹配的方式非常高效,特别是对于具有微不足道的 ctors 和 dtors 的普通旧数据类型。同样,这是十多年前的事了,但我发现将填充构造函数与 vector<int> 一起使用在 MSVC 5 或 6(忘记是哪一个)中实际上转换为与使用相同的反汇编 memset以我天真的版本的方式,只是循环遍历事物并在它们上使用 placement new 而不管它们是否是 POD,没有。范围 ctor 也有效地转换为超快 memcpy对于 POD。而这正是让 vector 对我来说如此难以击败的原因,至少在当时是这样。如果不深入研究类型特征和特殊外壳 POD,我无法真正匹配 POD 的 vector 性能。我可以将它与 UDT 相匹配,但我们的大多数性能关键代码都倾向于使用 POD。

因此,今天流行的 vector 实现很可能与我进行这些测试时一样高效,如果不是更高的话,我想在某种程度上作为一种保证,你的 vector 实现很可能非常快。我最不希望它做的是使用 push_backs 实现填充 ctors 或范围 ctors .

关于c++ - vector<T>::push_back 用于预定义的构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47144488/

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