gpt4 book ai didi

c++ - 为什么 .push_back(x) 比 .push_back(std::move(x)) 快

转载 作者:行者123 更新时间:2023-12-03 10:05:06 38 4
gpt4 key购买 nike

我有一个很大的 .txt 文件,需要加载并存储在 vector 中。该文件大小约为 5MB,500 000 行,每行约 10-20 个字符,以 '\n' 分隔。我正在使用以下示例代码对读取整个文件所需的时间进行一些基准测试:

#include<iostream>
#include<vector>
#include<fstream>

int main()
{
std::fstream input("words.txt");
std::vector<std::string> vector;
std::string line;

while(input >> line){
vector.push_back(line);
}
}
我很好奇将字符串作为右值引用传递是否会更快,但它会慢约 10 毫秒。
#include<iostream>
#include<vector>
#include<fstream>

int main()
{
std::fstream input("words.txt");
std::vector<std::string> vector;
std::string line;

while(input >> line){
vector.push_back(std::move(line));
}
}
第一个代码示例的平均加载时间约为 58 毫秒,第二个代码示例的平均加载时间为 68-70 毫秒。我在想 move 总是更快或等于复制,这就是为什么这对我来说似乎不正确。
有谁知道发生这种情况的原因?
基准测试是使用以下方法完成的:
perf stats -r 100 ./a.out
在 Arch Linux 上,代码已使用 GCC 10.2、C++17 std 编译。
此外,如果有人知道这样做的更佳方法,我们将不胜感激。

最佳答案

如果您调用 g++ -E您可以查看相关代码:
复制构造:

  basic_string(const basic_string& __str)
: _M_dataplus(_M_local_data(),
_Alloc_traits::_S_select_on_copy(__str._M_get_allocator()))
{
_M_construct(__str._M_data(), __str._M_data() + __str.length());
}
move build :
# 552 "/usr/local/include/c++/10.2.0/bits/basic_string.h" 3
basic_string(basic_string&& __str) noexcept
: _M_dataplus(_M_local_data(), std::move(__str._M_get_allocator()))
{
if (__str._M_is_local())
{
traits_type::copy(_M_local_buf, __str._M_local_buf,
_S_local_capacity + 1);
}
else
{
_M_data(__str._M_data());
_M_capacity(__str._M_allocated_capacity);
}
_M_length(__str.length());
__str._M_data(__str._M_local_data());
__str._M_set_length(0);
}
值得注意的是,(为了支持短字符串优化) move 构造函数需要查看 ._M_is_local()计算是复制还是 move (因此有一个分支要预测),并清除 move 的字符串/将其长度设置为 0。额外的工作 = 额外的时间。

@Manuel 发表了一个有趣的评论:

When you move line it gets empty, so the next iteration needs to allocate space. std::string has a small buffer as an optimization (most of the implementations, if not all) and the copy just copies chars, no memory allocation. That could be the difference.


这并不像所说的那样加起来,但这里有细微的差别。对于输入空格分隔的单词足够长以需要动态分配,:
a) move 版本可能已清除 line最后一个字之后的动态缓冲区,因此需要重新分配;如果输入足够长,则可能需要重新分配一次或多次以增加容量。
b) 复制版本可能有足够大的缓冲区(其容量将根据需要增加,有效地成为所见单词的高水位线),但是在 push_back 内部构建复制时将需要动态分配.不过,该分配的确切大小是预先知道的——不需要调整大小来增加容量。
这确实表明当输入字长有很多变化时,复制可能会更快。

Also if anyone knows a more optimal way to do this would be much appreciated.


如果您真的很关心性能,我建议您对映射文件的内存进行基准测试并创建 vectorstring_view进入它:这可能会快得多。

关于c++ - 为什么 .push_back(x) 比 .push_back(std::move(x)) 快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65062713/

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