获取嵌套 stl 容器的字节大小
Getting the size in bytes of nested stl containers
我已经知道 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++ 容器的 None 公开了关于它们分配了多少内存的指示器。将 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>
不会将分配器正确转发到它们的嵌套元素。在这些情况下,如果元素使用分配,则无法正确确定已用内存。
首先,没有 "easy" 计算来自 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;
}
和 copy/paste 与您拥有的所有模板接口相同的代码,例如对于集合:
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);
}
但正如其他人指出的那样,您只会计算原始数据的大小,这远非准确。 The memory usage of STL containers can be surprising.
我已经知道 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>
使用相同的方法?
None 公开了关于它们分配了多少内存的指示器。将 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>
不会将分配器正确转发到它们的嵌套元素。在这些情况下,如果元素使用分配,则无法正确确定已用内存。
首先,没有 "easy" 计算来自 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;
}
和 copy/paste 与您拥有的所有模板接口相同的代码,例如对于集合:
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);
}
但正如其他人指出的那样,您只会计算原始数据的大小,这远非准确。 The memory usage of STL containers can be surprising.