c++字符串使用分配的最大缓冲区
C++ string uses maximum buffer allocated?
我声明一个变量string s;
和做s = "abc";
现在它有3个字符的缓冲区。
s = "abcd"
有一个4个字符的缓冲区。
现在在第三条语句
之后 s = "ab"
问题是它会保留4个字符的缓冲区还是会重新分配2个字符的缓冲区?
如果它将分配2个字符的缓冲区,我可以告诉它保持分配的最大缓冲区。
那么它是否保持分配的缓冲区的最大大小呢?
s = "ab"
s="abc"
s="a"
s="abcd"
s="b"
现在它应该保留一个大小为4的缓冲区。
这可能吗?
一旦分配,字符串将保留其缓冲区,只有在需要更大的缓冲区时才会重新分配。它也可能以大于3或4的初始缓冲区大小开始。
可以通过capacity()
成员函数查看已分配的大小。
经过James下面的评论,我仍然相信我的答案对于问题中给出的例子是正确的。
但是,对于引用计数的实现,像这样的序列
s = "some rather long string...";
std::string t = "b";
s = t;
如果实现决定在s
和t
之间共享内部缓冲区,将s.capacity()
设置为等于t.capacity()
。
s = "ab"的问题是它是否会保留4个单词的缓冲区重新分配2字缓冲区?
它不会重新分配缓冲区。我不知道标准中是否提到了这一点,但我所见过的所有实现只有在需要增加容量时才会重新分配。永远不要减少。即使您有一个4个字符的字符串并调用.resize(2)
或.reserve(2)
,容量也不会改变。为了强制字符串(或容器)重新分配内存以适应确切的大小,有一个简单的swap
技巧用于
s.swap(string(s));
这里发生了什么?您从s创建一个临时的,它的容量将完全等于s.size()
,然后将它与原始字符串交换。临时函数的析构函数将释放所有必需的资源。
再次强调,我并不是说这是标准的,但是我所见过的所有实现都有这种行为。
通过调用,可以很容易地看到实现的行为std::string::capacity
在不同时间。一般来说,我会感到惊讶如果任何实现都有三个字符的缓冲区。(不字,但字节,至少在大多数现代机器上。)在实践中,实现各不相同,并且还取决于新长度如何变化例如,在g++中,删除带有的字符std::string::erase
不会减少字符串的容量,但是赋值一个新的更小的字符串会。vc++不会减少容量无论哪种情况。(总的来说,vc++和g++有很大的不同关于字符串中内存管理的策略。)
考虑到其他响应(甚至不符合通常的响应)实践):这是我用来验证我的语句的小测试程序(虽然我真的不需要g++—我知道内部实现相当好):
#include <string>
#include <iostream>
#include <iomanip>
template<typename Traits>
void
test()
{
std::string s;
size_t lastSeen = -1;
std::cout << Traits::name() << ": Ascending:" << std::endl;
while ( s.size() < 150 ) {
if ( s.capacity() != lastSeen ) {
std::cout << " " << std::setw( 3 ) << s.size()
<< ": " << std::setw( 3 ) << s.capacity() << std::endl;
lastSeen = s.capacity();
}
Traits::grow( s );
}
std::cout << Traits::name() << ": Descending: " << std::endl;
while ( s.size() != 0 ) {
Traits::shrink( s );
if ( s.capacity() != lastSeen ) {
std::cout << " " << std::setw( 3 ) << s.size()
<< ": " << std::setw( 3 ) << s.capacity() << std::endl;
lastSeen = s.capacity();
}
}
std::cout << "Final: capacity = " << s.capacity() << std::endl;
}
struct Append
{
static void grow( std::string& s )
{
s += 'x';
}
static void shrink( std::string& s )
{
s.erase( s.end() - 1 );
}
static std::string name()
{
return "Append";
}
};
struct Assign
{
static void grow( std::string& s )
{
s = std::string( s.size() + 1, 'x' );
}
static void shrink( std::string& s )
{
s = std::string( s.size() - 1, 'x' );
}
static std::string name()
{
return "Assign";
}
};
int
main()
{
test<Append>();
test<Assign>();
return 0;
}
试试。
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 如何分配适合容纳 T 类型对象的缓冲区(可能过度对齐、可能有运算符 new 等)
- char p[0]表示自动分配的缓冲区还是安全指针
- 有没有办法自动实现 sprintf 的缓冲区分配?
- 线程函数无法从堆上分配的缓冲区中读取字符
- 如何正确分配Fuse ReadDir()的缓冲区
- 将数据分配给了数组分配,但程序显示了以缓冲区超支的输出
- C++:当我将值分配给缓冲区时,它不起作用
- 如何在 OpenCL 中使用缓冲区分配和映射内存机制
- 从C 中的函数中动态分配的缓冲区返回的最佳模式是什么?
- 了解循环缓冲区实现的内存分配性质
- 尝试为图像缓冲区分配内存时 ptr 值错误
- Sprintf 缓冲区问题,错误分配给字符数组
- Vulkan中动态统一缓冲区的缓冲区内存分配
- 如何分配可执行的内存缓冲区
- C - 分配一个未签名的炭缓冲区,然后用字符串填充
- 包含溢出缓冲区的堆栈分配变量,也称为缓冲区
- 使用 sprintf 分配给字符数组并将字符指针作为输入之一时缓冲区溢出
- 静态数组缓冲区分配
- OpenCL缓冲区分配和映射最佳实践