获取嵌套 stl 容器的大小(以字节为单位)

Getting the size in bytes of nested stl containers

本文关键字:字节 为单位 stl 嵌套 获取      更新时间:2023-10-16

我已经知道std::vector<int>我可以这样做:

std::vector<int> v;
// populate v
std::size_t bytes = sizeof(std::vector<int>) + sizeof(int) * v.size();

但是,获取大小的正确方法是什么std::vector<std::set<std::array<int, 10>>>的字节数?我是否必须递归地调用 sizeof 到所有嵌套容器?例:

std::vector<std::set<std::array<int, 10>>> v;
// populate v
std::size_t bytes = sizeof(v);
for(auto& s : v)
{
bytes += sizeof(s);
for(auto& a : s)
{
bytes += sizeof(a) + sizeof(int) * 10;
}
}

还是我只是对顶级容器中的std::vector<int>使用相同的方法?

标准C++容器都不会公开有关它们分配多少内存的指示器。将std::vector<T> v的已分配内存计算为sizeof(v) + v.capacity() * sizeof(T)似乎是可行的(因为std::vector<T>必须使用v.size()而不是v.capacity()过度分配以满足其性能约束,这是错误的(。但是,不能保证这给出了正确的值。虽然我不知道有任何标准的库实现可以做到这一点,但我可以想象用指向第一个元素的指针实现vector<T>,该元素前面有一个存储末端、容量和分配器的控制块。

大多数容器使用内部节点,例如,指向std::list中上一个和下一个节点的指针,或指向有序关联容器使用的树中的子节点的指针。对这些节点的大小没有很好的估计,因为可能包含额外的控制信息。此外,内存分配可以使用与分配块的一些信息,例如,分配块的大小。

估计任何这些数据结构的分配大小的唯一潜在方法是使用自定义分配器来跟踪使用的内存量。当然,使用这种方法意味着容器中的任何子对象也正确地使用分配器作为其重复分配的内存。请注意,某些标准容器(例如,std::array<T, N>(没有正确地将分配器转发到其嵌套元素。在这些情况下,如果元素使用分配,则无法正确确定使用的内存。

首先,没有"简单"的方法来计算STL中所有内容的存储。

在您尝试之后,我能想到的最好的就是编写您自己的sizeof函数,您将为喜欢的所有内容实现该函数,例如:

template<typename T>
size_t metaSizeOf(const T& t)
{
return sizeof(T);
}

然后随意对其进行专用化,例如对于一个向量,您需要类似的东西:

template<typename T, typename Alloc, template <typename, typename> class V>
size_t metaSizeOf(const V<T, Alloc>& v)
{
size_t bytes = sizeof(V<T, Alloc>);
for(const auto& t: v) bytes += metaSizeOf(t);
return bytes;
}

并使用您拥有的所有模板接口复制/粘贴相同的代码,例如对于集合:

template<typename T, typename Compare, typename Alloc, template <typename, typename, typename> class V>
size_t metaSizeOf(const V<T, Compare, Alloc>& v)
{
size_t bytes = sizeof(V<T, Compare, Alloc>);
for(const auto& t: v) bytes += metaSizeOf(t);
return bytes;
}

等等。您还可以针对特定情况编写自己的实现。例如,对于数组,您可以编写一个泛型函数:

template<typename T, std::size_t N, template <typename, std::size_t> class V>
size_t metaSizeOf(const V<T, N>& v)
{
size_t bytes = sizeof(V<T, N>);
for(const auto& t: v) bytes += metaSizeOf(t);
return bytes;
}

但您也可以仅为阵列选择专用的优化版本:

template<typename T, std::size_t N>
size_t metaSizeOf(const std::array<T, N>&)
{
return sizeof(std::array<T, N>) + N * sizeof(T);
}

示例 @ IdeOne.com

但正如其他人指出的那样,您只会计算原始数据的大小,这远非准确。STL 容器的内存使用量可能令人惊讶。