我正在调查一种情况,其中消耗了更多的内存而不是所需的内存。如果我为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字节)都为副本分配分配的内存比为副本构造分配的内存更多?在这两种情况下,都知道新的大小。我看不到其中的哪一种将来更有可能需要额外的内存。
答案 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()
。