我正在处理程序中的很多字符串。 这些字符串数据在读入我的程序后不会在整个生命周期内发生变化。
但是由于C ++字符串保留了容量,它们会浪费大量空间,而这些空间肯定无法使用。 我试图释放这些空格,但它没有用。
以下是我尝试过的简单代码:
string temp = "1234567890123456";
string str;
cout << str.capacity() << endl;
str.reserve(16);
cout << str.capacity() << endl;
// capacity is 31 on my computer
str += temp;
cout << str.capacity() << endl;
str.reserve(16);
cout << str.capacity() << endl;
// can't release. The capacity is still 31.
(编译器是Visual C ++)
我怎么能释放它?
答案 0 :(得分:12)
当您致电reserve
时,您正在发出请求来更改容量。实现仅保证保留等于或大于此数量的数字。 因此,特定实施可能会安全地忽略对缩小容量的请求。
但是,我鼓励您考虑这是不是过早优化。你确定你真的在制作这么多字符串,这对你来说是一个内存瓶颈吗?你确定它实际上是内存是瓶颈吗?
来自reserve
的文档:
这可以扩大或缩小尺寸 字符串中的存储空间, 虽然注意到了结果 调用此函数后的容量 不一定等于
res_arg
但可以相等或更大 比res_arg
,因此缩小 请求可能会也可能不会产生 实际减少分配 特定图书馆的空间 实现。无论如何,它永远不会 修剪字符串内容(为此 目的,请参阅调整大小或清除,其中 修改内容)。
答案 1 :(得分:5)
为什么不使用char数组?
答案 2 :(得分:4)
string x = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
cerr << x.capacity() << "\n"; // MSVC++: 63 g++: 52
// This tends not to work (although in theory it could):
//x = "XYZ";
//cerr << x.capacity() << "\n"; // MSVC++: 63 g++: 52
// This tends to work (although in theory it might not):
string("XYZ").swap(x);
cerr << x.capacity() << "\n"; // MSVC++: 15 g++: 3
请注意,如果底层分配器在构造长度 n 的string
时分配的内容超过 n 个字节(例如,通过向上舍入到最接近的32作为MSVC ++似乎这样做,没有办法让它使用更少的字节。但是你可能不想这样做,因为这种“四舍五入”是为了使动态内存分配过程更有效,并且还具有使短字符串串联更快的副作用(因为需要更少的重新分配)发生)。
答案 3 :(得分:4)
尝试使用std::string
swap-trick缩小字符串:
std::string( str.data(), str.size() ).swap( str )
其中str
是您想要减小尺寸的字符串。
答案 4 :(得分:3)
我认为您可以使用swap方法释放数据。将它与空的本地字符串交换,以便当本地字符串超出范围时释放内存。
答案 5 :(得分:1)
这主要是针对具体实施的。我们的想法是最小化分配请求和内存碎片。很容易证明,每次扩展块时,通过将现有大小加倍,分配计数和内存碎片都会被最小化。因此,在扩展时,通常STL容器实现将使现有块加倍。
你可以做的一件事是使用一个不会分配超过必要的自定义分配器,接下来,当你不再需要操作它们时构造你的std :: string对象(或者当完成操作时,只需交换到新的std) :: sting对象 - 这基本上是其他人在他们的答案中所做的事情)最后,你可以使用一个池内存分配器来最小化内存碎片,浪费松弛并提高性能。
请参阅:
http://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c4079 http://www.sjbrown.co.uk/2004/05/01/pooled-allocators-for-the-stl/ http://www.codeproject.com/KB/stl/blockallocator.aspx
搜索“STL分配器”和“内存池”
答案 6 :(得分:0)
std::string
没有保证最低容量。您可以通过调用reserve
来请求任何容量,但特定实现仅保证将容量设置为大于或等于请求大小的某个数量。
以下是程序的修改版本,它测试了几种字符串收缩方法:
#include <string>
#include <iostream>
using namespace ::std;
template< typename S >
S & reserve_request( S & s, typename S::size_type n ) {
s.reserve( n ); return s;
}
template< typename S >
S & shrink_request1( S & s ) { s.reserve(); return s; }
template< typename S >
S & shrink_request2( S & s ) { S( s ).swap( s ); return s; }
template< typename S >
S & shrink_request3( S & s ) { S( s.c_str() ).swap( s ); return s; }
template< typename S >
void test( S & s ) { cout << s.capacity() << endl; }
int main() {
string temp = "1234567890123456"; // length 16
string str;
test( str ); // 15
test( reserve_request( str, 16 ) ); // 31
test( str += temp ); // 31
test( reserve_request( str, 16 ) ); // 31
test( shrink_request1( str ) ); // 31
test( shrink_request2( str ) ); // 31
test( shrink_request3( str ) ); // 31
return 0;
}
Visual C ++的std::string
通常会保留一些备用容量。
如果你的项目加载大量的字符串从外部源读入,而外部源的大小永远不会改变,你可能会更好(正如其他人所建议的那样)将它们存储在由{{1}分隔的单个大块字符存储器中字符(即,作为C字符串)。如果您愿意,可以提供即时返回'\0'
的包装函数。
答案 7 :(得分:0)
查看xstring头文件
在您保留的示例16中,您实际上保留了17(一个为null),这是&gt;因此,在缓存指针联合中的16字节中分配而不是缓存。该分配使之前的大小加倍(16),因此你得到32.那个字符串的容量大概是31。
但这是STL实现依赖。
更改std :: basic_string的模板decl中的allocator模板参数是不够的 - 选择何时分配和多少,在std :: basic_string中增长算法不在分配器中。先前大小的倍增(和<1/4时缩小)是算法导论中的标准内容 - Cormen Lieserson Rivest Stein
不确定dinkumware中缩小的算法.......