C++ std::strings 的 capacity()、reserve() 和 resize() 函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9521629/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:55:17  来源:igfitidea点击:

std::strings's capacity(), reserve() & resize() functions

c++stringstl

提问by zar

I wan to use std::string simply to create a dynamic buffer and than iterate through it using an index. Is resize() the only function to actually allocate the buffer?

我想使用 std::string 来创建一个动态缓冲区,然后使用索引对其进行迭代。resize() 是实际分配缓冲区的唯一函数吗?

I tried reserve() but when I try to access the string via index it asserts. Also when the string's default capacity seems to be 15 bytes (in my case) but if I still can't access it as my_string[1].

我试过 Reserve() 但是当我尝试通过索引访问字符串时,它会断言。此外,当字符串的默认容量似乎是 15 个字节(在我的情况下)但如果我仍然无法以my_string[1].

So the capacity of the string is not the actual buffer? Also reserve() also does't allocate the actual buffer?

那么字符串的容量不是实际的缓冲区?还保留()也不分配实际缓冲区?

string my_string;

// I want my string to have 20 bytes long buffer
my_string.reserve( 20 );

int i = 0;

for ( parsing_something_else_loop )
{
    char ch = <business_logic>;

    // store the character in 
    my_string[i++] = ch; // this crashes
}

If I do resize() instead of reserve() than it works fine. How is it that the string has the capacity but can't really access it with []? Isn't that the point to reserve() size so you can access it?

如果我做 resize() 而不是 reserve() ,它工作正常。字符串有容量但不能真正用[]访问它是怎么回事?这不是保留()大小以便您可以访问它的要点吗?

Add-onIn response to the answers, I would like to ask stl folks, Why would anybody use reserve() when resize() does exactly the same and it also initialize the string? I have to say I don't appreciate the performance argument in this case that much. All that resize() does additional to what reserve() does is that it merely initialize the buffer which we know is always nice to do anyways. Can we vote reserve() off the island?

附加组件 作为对答案的回应,我想问 stl 人,当 resize() 完全相同并且它还初始化字符串时,为什么有人会使用 Reserve()?我不得不说我不太欣赏这种情况下的性能论点。除了reserve() 所做的之外,resize() 所做的只是初始化缓冲区,我们知道无论如何这样做总是很好的。我们可以在岛外投票吗?

回答by kennytm

Isn't that the point to reserve() size so you can access it?

这不是保留()大小以便您可以访问它的要点吗?

No, that's the point of resize().

不,这就是重点resize()

reserve()only gives to enough room so that future call that leads to increase of the size (e.g. calling push_back()) will be more efficient.

reserve()只提供足够的空间,以便将来导致大小增加的调用(例如调用push_back())将更有效率。

From your use case it looks like you should use .push_back()instead.

从您的用例看来,您应该.push_back()改用。

my_string.reserve( 20 );

for ( parsing_something_else_loop )
{
    char ch = <business_logic>;
    my_string.push_back(ch);
}


How is it that the string has the capacity but can't really access it with []?

字符串有容量但不能真正用[]访问它是怎么回事?

Calling .reserve()is like blowing up mountains to give you some free land. The amount of free land is the .capacity(). The land is there but that doesn't mean you can live there. You have to build houses in order to move in. The number of houses is the .size()(= .length()).

打电话.reserve()就像炸山给你一些免费的土地。自由土地的数量是.capacity()。土地在那里,但这并不意味着你可以住在那里。你必须盖房子才能搬进来。房子的数量是.size()(= .length())。

Suppose you are building a city, but after building the 50th you found that there is not enough land, so you need to found another place large enough to fit the 51st house, and then migrate the whole population there. This is extremely inefficient. If you knew you need to build 1000 houses up-front, then you can call

假设你正在建造一座城市,但在建造了第 50 座之后,你发现没有足够的土地,所以你需要另找一个足够容纳 51 座房子的地方,然后将所有人口迁移到那里。这是非常低效的。如果您知道需要预先建造 1000 座房屋,那么您可以致电

my_string.reserve(1000);

to get enough land to build 1000 houses, and then you call

获得足够的土地来建造 1000 所房子,然后你打电话

my_string.push_back(ch);

to construct the house with the assignment of chto this location. The capacity is 1000, but the size is still 1. You may not say

建造房子,分配ch到这个位置。容量是1000,但大小还是1。你可能不会说

my_string[16] = 'c';

because the house #16 does not exist yet. You may call

因为房子 #16 还不存在。你可以打电话

my_string.resize(20);

to get houses #0 ~ #19 built in one go, which is why

一口气建好房子#0 ~ #19,这就是为什么

my_string[i++] = ch;

works fine (as long as 0 ≤ i≤ 19).

工作正常(只要 0 ≤ i≤ 19)。

See also http://en.wikipedia.org/wiki/Dynamic_array.

另见http://en.wikipedia.org/wiki/Dynamic_array



For your add-on question,

对于您的附加问题,

.resize()cannot completely replace .reserve(), because (1) you don't always need to use up all allocated spaces, and (2) default construction + copy assignment is a two-step process, which could take more time than constructing directly (esp. for large objects), i.e.

.resize()不能完全替换.reserve(),因为 (1) 你并不总是需要用完所有分配的空间,并且 (2) 默认构造 + 复制赋值是一个两步过程,这可能比直接构造花费更多的时间(特别是对于大型对象),即

#include <vector>
#include <unistd.h>

struct SlowObject
{
    SlowObject() { sleep(1); }
    SlowObject(const SlowObject& other) { sleep(1); }
    SlowObject& operator=(const SlowObject& other) { sleep(1); return *this; }
};

int main()
{
    std::vector<SlowObject> my_vector;

    my_vector.resize(3);
    for (int i = 0; i < 3; ++ i)
        my_vector[i] = SlowObject();

    return 0;
}

Will waste you at least 9 seconds to run, while

会浪费你至少 9 秒的运行时间,而

int main()
{
    std::vector<SlowObject> my_vector;

    my_vector.reserve(3);
    for (int i = 0; i < 3; ++ i)
        my_vector.push_back(SlowObject());

    return 0;
}

wastes only 6 seconds.

仅浪费6秒。

std::stringonly copies std::vector's interface here.

std::stringstd::vector这里只复制的界面。

回答by Jerry Coffin

No -- the point of reserveis to prevent re-allocation. resizesets the usable size, reservedoes not -- it just sets an amount of space that's reserved, but not yet directly usable.

不——重点reserve是防止重新分配。resize设置可用大小,reserve不 - 它只是设置保留的空间量,但尚未直接可用。

Here's one example -- we're going to create a 1000-character random string:

这是一个例子——我们将创建一个 1000 个字符的随机字符串:

static const int size = 1000;
std::string x;
x.reserve(size);
for (int i=0; i<size; i++)
   x.push_back((char)rand());

reserveis primarilyan optimization tool though -- most code that works with reserveshould also work (just, possibly, a little more slowly) without calling reserve. The one exception to that is that reservecan ensure that iterators remain valid, when they wouldn't without the call to reserve.

reserve不过,它主要是一个优化工具——大多数可以使用的代码也reserve应该在不调用reserve. 一个例外是reserve可以确保迭代器保持有效,而如果没有调用 Reserve 的话。

回答by dasblinkenlight

The capacityisthe length of the actual buffer, but that buffer is privateto the string; in other words, it is not yours to access. The std::stringof the standard library mayallocate more memory than is required to storing the actual characters of the string. The capacity is the total allocated length. However, accessing characters outside s.begin()and s.end()is still illegal.

capacity实际的缓冲区的长度,但该缓冲器是私有的字符串; 换句话说,访问不是你的。的std::string标准库的分配比需要存储该字符串的实际字符更多的内存。容量是分配的总长度。然而,外界访问字符s.begin()s.end()仍然是非法的。

You call reservein cases when you anticipate resizing of the string to avoid unnecessary re-allocations. For example, if you are planning to concatenate ten 20-character strings in a loop, it may make sense to reserve 201 characters (an extra one is for the zero terminator) for your string, rather than expanding it several times from its default size.

reserve当您预计调整字符串大小以避免不必要的重新分配时,您可以调用。例如,如果您计划在循环中连接 10 个 20 个字符的字符串,则为您的字符串保留 201 个字符(一个额外的字符用于零终止符)可能是有意义的,而不是将其从默认大小扩展数次.

回答by Christian Rau

reserve(n)indeed allocates enough storage to hold at least nelements, but it doesn't actually fill the container with any elements. The string is still empty (has size 0), but you are guaranteed, that you can add (e.g. through push_backor insert) at least nelements before the string's internal buffer needs to be reallocated, whereas resize(n)really resizes the string to contain nelements (and deletes or adds new elements if neccessary).

reserve(n)确实分配了足够的存储空间来容纳至少n元素,但它实际上并没有用任何元素填充容器。字符串仍然是空的(大小为 0),但您可以保证,在需要重新分配字符串的内部缓冲区之前,您可以添加(例如,通过push_backinsert)至少n元素,而resize(n)真正调整字符串的大小以包含n元素(并删除或如果需要,添加新元素)。

So reserveis actually a mere optimization facility, when you know you are adding a bunch of elements to the container (e.g. in a push_backloop) and don't want it to reallocate the storage too often, which incurs memory allocation and copying costs. But it doesn't change the outside/client view of the string. It still stays empty (or keeps its current element count).

所以reserve实际上只是一个优化工具,当您知道要向容器添加一堆元素(例如在push_back循环中)并且不希望它过于频繁地重新分配存储时,这会导致内存分配和复制成本。但它不会改变字符串的外部/客户端视图。它仍然保持为空(或保持其当前元素计数)。

Likewise capacityreturns the number of elements the string can hold until it needs to reallocate its internal storage, whereas size(and for string also length) returns the actual number of elements in the string.

同样capacity返回字符串在需要重新分配其内部存储之前可以保存的元素数,而size(对于 string 也是length)返回字符串中的实际元素数。

回答by Branko Dimitrijevic

Just because reserveallocates additional space does not mean it is legitimate for you to access it.

仅仅因为reserve分配了额外的空间并不意味着您可以合法地访问它。

In your example, either use resize, or rewrite it to something like this:

在您的示例中,要么使用resize,要么将其重写为如下所示:

string my_string;

// I want my string to have 20 bytes long buffer
my_string.reserve( 20 );

int i = 0;

for ( parsing_something_else_loop )
{
    char ch = <business_logic>;

    // store the character in 
    my_string += ch;
}

回答by J?rg Beyer

std::vectorinstead of std::stringmight also be a solution - if there are no requirements against it.

std::vector而不是std::string也可能是一个解决方案 - 如果没有针对它的要求。

vector<char> v; // empty vector
vector<char> v(10); // vector with space for 10 elements, here char's

your example:

你的例子:

vector<char> my_string(20);

int i=0;

for ( parsing_something_else_loop )
{
    char ch = <business_logic>;
    my_string[i++] = ch;
}