C ++ строка использует максимальный выделенный буфер? - PullRequest
6 голосов
/ 28 июля 2011

Я объявляю переменную 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 ]

10 голосов
/ 28 июля 2011

Строка сохранит свой буфер, как только он будет выделен, и будет перераспределяться только в том случае, если ему нужен еще больший буфер.Вероятно, он также начнется с начального размера буфера больше 3 или 4.

Вы можете проверить выделенный размер, используя функцию-член capacity().


После комментариев Джеймса нижеЯ все еще считаю, что мой ответ правильный для примеров, приведенных в вопросе.

Однако для реализации с подсчетом ссылок последовательность, подобная этой

s = "some rather long string...";

std::string t = "b";
s = t;

, установит s.capacity() равным t.capacity(), если реализация решит разделить внутренний буфер между s и t.

7 голосов
/ 28 июля 2011

s = "ab" вопрос в том, сохранит ли он буфер из 4 слов или перераспределит буфер из 2 слов?

Он не будет перераспределять буфер.Я не знаю, упоминается ли это в стандарте, но все реализации, которые я когда-либо видел, выдают перераспределение, только если им нужно увеличить емкость.Никогда не уменьшаться.Даже если у вас есть строка из 4 символов и вызовите .resize(2) или .reserve(2), емкость не изменится.Чтобы заставить строку (или контейнеры) перераспределить память, чтобы она соответствовала точному размеру, для этого есть простой swap трюк

s.swap(string(s));

Что здесь происходит?Вы создаете временную переменную из s, которая будет иметь емкость, равную s.size(), а затем меняете ее на исходную строку.Деструктор временного освободит все необходимые ресурсы.

Опять же, я не утверждаю, что это стандарт, но все реализации, которые я видел, имеют такое поведение.

0 голосов
/ 28 июля 2011

Вы можете легко увидеть поведение вашей реализации, вызвав std::string::capacity в разное время. В общем, я бы удивился если любая реализация когда-либо имела буфер из трех символов. (Не слова, но байты, по крайней мере, на большинстве современных машин.) На практике, реализации варьируются, а также различаются в зависимости от того, как новая длина происходит с помощью g ++, например, удаление символов с std::string::erase не уменьшит емкость строки, но назначение новой, меньшей строки будет. VC ++ не уменьшает емкость в любом случае. (В общем, VC ++ и g ++ имеют очень разные стратегии в отношении управления памятью в строках.)

EDIT:

Учитывая другие ответы (которые даже не соответствуют обычным практика): вот небольшая тестовая программа, которую я использовал для проверки своих утверждений выше (хотя мне действительно не нужно это для g ++ & mdash; я знаю внутренности реализации неплохо):

#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;
}

Попробуй. Результаты весьма поучительны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...