根据 cppreference,
std::vector::assign
将内容替换为值 count
的 value
副本。 该定义意味着向量的现有状态未在 assign
中使用。
在以下示例代码中,在 GCC 14.2 上运行,
test1
打印 20000002
。 这表示分配新空间后现有内存将被删除。 通过适当放置 clear()
和 shrink_to_fit()
调用,test2
减少峰值对象计数并打印 10000002
。
这是在实现
libstdc++
时错过了优化机会还是我对std::vector
功能的理解不正确/不完整?
#include <iostream>
#include <vector>
int curr;
int max;
void update(int delta) { curr += delta; max = std::max(max, curr); }
void reset() { curr = max = 0; }
struct Foo {
Foo() { update(1); }
Foo(const Foo&) { update(1); }
Foo& operator=(const Foo&) { return *this; }
~Foo() { update(-1); }
};
void test1()
{
reset();
std::vector<Foo> foos;
foos.assign(10'000'000, Foo{});
foos.assign(10'000'001, Foo{});
std::cout << max << '\n';
}
void test2()
{
reset();
std::vector<Foo> foos;
foos.assign(10'000'000, Foo{});
foos.clear();
foos.shrink_to_fit();
foos.assign(10'000'001, Foo{});
std::cout << max << '\n';
}
int main()
{
test1();
test2();
return 0;
}
我觉得有点混乱。您实际测量的是对构造函数和析构函数的调用量,而不是它使用的内存量。
在这种情况下,对
shrink_to_fit()
的调用没有任何意义,它只是保证对具有更大数量元素的 assign
进行底层重新分配。
观察到的 20mil 意味着有一个时刻,第二个
assign
创建了对象,但第一个 assign
的对象尚未删除。
事实上,第二个
assign
是更大。因此,如果向量为第一个assign
分配了确切数量的内存,那么对于第二个assign
,它应该创建另一个内存块。它将创建第二对象负载,将max
的值增加到2000万。
然后释放为前 1000 万个元素分配的内存。
不会提前释放第一个内存块,因为在构造第二个内存块的过程中可能会出现异常。 因此,当保证第二个内存块的分配和填充成功时,第一个内存块就被释放了。