Почему std :: vector :: operator = overallocate памяти? - PullRequest
0 голосов
/ 13 апреля 2019

Я расследую случай, когда потребляется больше памяти, чем необходимо.Если я назначаю строку для std::vector, она внезапно резервирует больше памяти кучи, чем необходимо, даже если размер строки уже известен:

Вот что я разбил на:

#include <vector>
#include <iostream>
#include <new>

void* operator new(size_t size) { 
    void * p = malloc(size); 
    std::cout << "\talloc " << size << " @ " << p; 
    return p;
} 

void operator delete(void* p) { 
    std::cout << "\t      free " << p; 
    free(p);
} 

int main() {
    {
        std::cout << std::endl << "1. Create first string:   ";
        auto s1 = std::string{"String with 20 chars"};

        std::cout << std::endl << "2. Create longer string:  ";
        auto s2 = std::string{"String with 25 characters"};

        std::cout << std::endl << "3. Copy construct:        ";
        auto s3 = s2;

        std::cout << std::endl << "4. Copy assign:           ";
        s1 = s3;

        std::cout << std::endl << "5. Leaving scope:         ";
    }
    std::cout << std::endl;
}

Результат:

1. Create first string:     alloc 21 @ 0x56047f176280
2. Create longer string:    alloc 26 @ 0x56047f1762a0
3. Copy construct:          alloc 26 @ 0x56047f1762d0
4. Copy assign:             alloc 41 @ 0x56047f176300         free 0x56047f176280
5. Leaving scope:                 free 0x56047f1762d0         free 0x56047f1762a0         free 0x56047f176300

Я ожидаю, что строка 4 будет такой же, как и строка 3.

Почему и libstdc ++ (этот результат), и libc ++ (32 /48 байт) выделить больше памяти для назначения копирования, чем для создания копии? В обоих случаях известен новый размер.Я не могу понять, как одному из них, скорее всего, потребуется дополнительная память в будущем.

1 Ответ

0 голосов
/ 13 апреля 2019

Я обнаружил это в реализации basic_string в libstdc ++.operator=(const basic_string&) вызывает this->assign, который вызывает _M_assign, который вызывает _M_create с новой (минимальной) и старой емкостью.Здесь первоначальная емкость удваивается.Ссылка на политику экспоненциального роста включена в качестве комментария.

Во-первых, я не понял, как это связано с моим примером.В конце концов, я просто хочу заменить значение.

Политика роста для operator=(const basic_string&) имеет больше смысла, когда вместо одного назначения вы рассматриваете этот код:

std::string s;
for (auto i = 100; i < 110; ++i) s = s + std::to_string(i);

Здесьустановка емкости так, чтобы она «просто подходила», нарушила бы требование линейного роста.

Чтобы решить проблему потребления памяти, я сейчас вызываю shrink_to_fit() для целевой строки.

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