如何释放字符串的未使用容量

时间:2009-04-11 12:51:17

标签: c++ string visual-c++ memory-management

我正在处理程序中的很多字符串。 这些字符串数据在读入我的程序后不会在整个生命周期内发生变化。

但是由于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 ++)

我怎么能释放它?

8 个答案:

答案 0 :(得分:12)

当您致电reserve时,您正在发出请求来更改容量。实现仅保证保留等于或大于此数量的数字。 因此,特定实施可能会安全地忽略对缩小容量的请求。

但是,我鼓励您考虑这是不是过早优化。你确定你真的在制作这么多字符串,这对你来说是一个内存瓶颈吗?你确定它实际上是内存是瓶颈吗?

来自reserve的文档:

  

这可以扩大或缩小尺寸   字符串中的存储空间,   虽然注意到了结果   调用此函数后的容量   不一定等于res_arg   但可以相等或更大   比res_arg,因此缩小   请求可能会也可能不会产生   实际减少分配   特定图书馆的空间   实现。无论如何,它永远不会   修剪字符串内容(为此   目的,请参阅调整大小或清除,其中   修改内容)。

答案 1 :(得分:5)

为什么不使用char数组?

答案 2 :(得分:4)

拼出Naveen's answer

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)

使用dinkumware STL,容量永远不会低于15。 std :: basic_string有一个union,它是指向分配缓冲区或16字节缓冲区的指针(如果capacity()&lt; = 15)(对于char字符串)

查看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中缩小的算法.......