为什么std :: vector :: operator =整体分配内存?

时间:2019-04-13 16:15:26

标签: c++ string stl

我正在调查一种情况,其中消耗了更多的内存而不是所需的内存。如果我为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 :(得分:0)

我在libstdc ++的basic_string实现中跟踪了它。 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()