我宣布变量string s;
并且s = "abc";
现在它有3个字符的缓冲区。
之后
s = "abcd"
它有一个4个字符的缓冲区。
现在在第三个陈述之后
s = "ab"
问题是它会保留4个字符的缓冲区还是重新分配2个字符的缓冲区?
如果它将分配2个字符缓冲区有任何方法我可以告诉它保持分配的最大缓冲区。
那么它是否保留了最大大小的缓冲区?
s = "ab"
s="abc"
s="a"
s="abcd"
s="b"
现在应该保留4号缓冲区。
这可能吗?
答案 0 :(得分:10)
字符串将在分配后保留其缓冲区,并且只有在需要更大的缓冲区时才重新分配。它也可能以初始缓冲区大小大于3或4开始。
您可以使用capacity()
成员函数检查分配的大小。
在詹姆斯的评论之后,我仍然相信我的答案对于问题中给出的例子是正确的。
然而,对于参考计数实现了这样的序列
s = "some rather long string...";
std::string t = "b";
s = t;
如果实现决定在s.capacity()
和t.capacity()
之间共享内部缓冲区,则会将s
设置为等于t
。
答案 1 :(得分:7)
s =“ab”问题是它会保留4个字的缓冲区还是它 重新分配2个字缓冲区?
它不会重新分配缓冲区。我不知道它是否在标准中提到过,但我所见过的所有实现只有在需要 增加 容量时才会发出重新分配。永远不要减少。即使您有一个包含4个字符的字符串并且调用.resize(2)
或.reserve(2)
,容量也不会更改。为了强制字符串(或容器)重新分配内存以适应确切的大小,有一个简单的swap
技巧
s.swap(string(s));
这里发生了什么?您可以创建一个临时的s,其容量将完全等于s.size()
,然后将其与原始字符串交换。临时的析构函数将释放所有必要的资源。
同样,我并不是说这是标准的,但我见过的所有实现都有这种行为。
答案 2 :(得分:0)
您可以通过调用轻松查看实现的行为
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;
}
试试吧。结果非常有启发性。