c++ - valgrind:多个 std::vector::resize 调用
问题描述
我一直在一个大型 C++ 代码库中追踪一个单独的问题。出于某种原因,我无法理解以下 Valgrind 行为。有人可以在这里阐明一下吗?
代码是:
% cat foo.cxx
#include <cstring>
#include <string>
#include <vector>
int main() {
std::vector<char> v;
#ifdef RESIZE9
v.resize(9);
#endif
v.resize(10);
std::string s(10, 'x');
std::strcpy(&v[0], s.c_str());
return 0;
}
这是预期的 Valgrind 输出:
% g++ foo.cxx && valgrind ./a.out
==21886== Memcheck, a memory error detector
==21886== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21886== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==21886== Command: ./a.out
==21886==
==21886== Invalid write of size 1
==21886== at 0x4838DD7: strcpy (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==21886== by 0x1092CA: main (in /tmp/a.out)
==21886== Address 0x4d84c8a is 0 bytes after a block of size 10 alloc'd
==21886== at 0x4835DEF: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==21886== by 0x109BCD: __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) (in /tmp/a.out)
==21886== by 0x109AD5: std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) (in /tmp/a.out)
==21886== by 0x109997: std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) (in /tmp/a.out)
==21886== by 0x1095E8: std::vector<char, std::allocator<char> >::_M_default_append(unsigned long) (in /tmp/a.out)
==21886== by 0x1093CC: std::vector<char, std::allocator<char> >::resize(unsigned long) (in /tmp/a.out)
==21886== by 0x10926A: main (in /tmp/a.out)
==21886==
==21886==
==21886== HEAP SUMMARY:
==21886== in use at exit: 0 bytes in 0 blocks
==21886== total heap usage: 2 allocs, 2 frees, 72,714 bytes allocated
==21886==
==21886== All heap blocks were freed -- no leaks are possible
==21886==
==21886== For counts of detected and suppressed errors, rerun with: -v
==21886== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
但现在考虑以下几点:
% g++ -DRESIZE9 foo.cxx && valgrind ./a.out
==21904== Memcheck, a memory error detector
==21904== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21904== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==21904== Command: ./a.out
==21904==
==21904==
==21904== HEAP SUMMARY:
==21904== in use at exit: 0 bytes in 0 blocks
==21904== total heap usage: 3 allocs, 3 frees, 72,731 bytes allocated
==21904==
==21904== All heap blocks were freed -- no leaks are possible
==21904==
==21904== For counts of detected and suppressed errors, rerun with: -v
==21904== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
系统是 Debian/10.9,具有:
% g++ --version
g++ (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
和
% valgrind --version
valgrind-3.14.0
解决方案
虽然我无法确认这是一个完整的(跨平台)“解决方案”,但在调整大小操作后添加一行来显示向量的实际容量可能会有所帮助:
#include <cstring>
#include <string>
#include <vector>
#include <iostream>
//#define RESIZE9 1
int main()
{
std::vector<char> v;
#ifdef RESIZE9
v.resize(9);
#endif
v.resize(10);
std::cout << v.capacity() << std::endl; // Show the actual allocated size
std::string s(10, 'x');
std::strcpy(&v[0], s.c_str());
return 0;
}
按原样运行此代码(Visual Studio、MSVC、Windows 10、64 位)显示容量为10
(并非意外)。但是,当该#define RESIZE9 1
行未注释时,显示的容量(在两次调整大小调用后)为13
.
我相信,增加额外的容量是在标准的要求范围内:只要新分配的向量有足够的容量来适应新的大小,就不会损坏任何东西。分配 4 个额外字节(而不仅仅是一个)最有可能优化内存管理。
推荐阅读
- r - 着色和垃圾箱位置问题
- angular - 尝试从 back4app 对象读取值并将其设置为变量但出现错误:无法设置未定义的属性“登录名”
- django - 如何将图像添加到 Django 的 Syndication RSS-feed
- javascript - 优化 Javascript 中嵌套对象和数组的减少
- python - 从给定的 csv 文件(销售数据)中使用 python 开发一个基本的搜索引擎
- swift - Swift枚举关联值作为函数参数
- ruby - 有没有办法用 update_columns 添加 default_scope 并在 rails 中删除
- javascript - 不允许未经身份验证的请求。SyntaxError:位置 0 处 JSON 中的意外标记 U
- ruby-on-rails - 使用 ActiveStorage 构建 Rails 6 应用程序,通过 dokku 成功部署,现在部署后图像消失
- python - 在 Pandas 中,如何将函数应用于数据框的一行,其中行中的每个项目都应作为参数传递给函数?