【问题标题】:What is the size of each element in std::list?std::list 中每个元素的大小是多少?
【发布时间】:2013-04-11 04:47:24
【问题描述】:

std::list 在其实现中使用链表,链表中的每个元素有多大(减去有效负载)?

通过测试,在 windows 7 机器上使用 mingw(不是 mingw-64),每个元素占用 24 个字节,用于 int 的每个元素。

一个指向左边的指针和一个指向右边的指针只有 4+4=8 个字节!而一个 int 只有 4 个字节(由 sizeof(void*) 和 sizeof(int) 决定),所以我很好奇,多余的空间去哪儿了?

(测试涉及制作许多元素,查看程序的大小,制作更多元素并再次查看程序的大小,获取差异)

【问题讨论】:

  • 推测:可能是一些字节对齐(填充)。
  • 检查源代码或在调试器中启动并打印。
  • 还有另一种方式:使用内存处理程序来跟踪程序使用的内存。然后创建一个新的list<T>。保存分配的内存。将T 附加到列表中。已用内存中的增量等于sizeof(list_node) + sizeof(T),因此从增量中减去sizeof(T) 得到sizeof(list_node)。
  • 根据gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a00577.html,它只有 2 个指针和有效负载。但是,如果使用 64 位编译器将其编译到库中,则指针将为 8 个字节,并且将其四舍五入为 24 的 4 个字节填充听起来是正确的。无论如何,这是我的猜测。我应该杀死这个问题吗?
  • 确保您在发布模式下进行测试。额外的空间可能是仅在调试模式下存在的安全功能。

标签: c++ stl


【解决方案1】:

当有关于 STL 容器的内存问题时...请记住,它们获得的所有内存都来自您传递的 分配器(默认为 std::allocator)。

因此,只需检测分配器即可回答大多数问题。现场演示位于liveworkspace,此处为std::list<int, MyAllocator>提供输出:

allocation of 1 elements of 24 bytes each at 0x1bfe0c0
deallocation of 1 elements of 24 bytes each at 0x1bfe0c0

因此,在这种情况下,24 字节,在 64 位平台上是可以预期的:两个指针用于下一个和上一个,4 字节有效负载和 4 字节填充。


完整的代码清单是:

#include <iostream>
#include <limits>
#include <list>
#include <memory>

template <typename T>
struct MyAllocator {
   typedef T value_type;
   typedef T* pointer;
   typedef T& reference;
   typedef T const* const_pointer;
   typedef T const& const_reference;
   typedef std::size_t size_type;
   typedef std::ptrdiff_t difference_type;

   template <typename U>
   struct rebind {
      typedef MyAllocator<U> other;
   };

   MyAllocator() = default;
   MyAllocator(MyAllocator&&) = default;
   MyAllocator(MyAllocator const&) = default;
   MyAllocator& operator=(MyAllocator&&) = default;
   MyAllocator& operator=(MyAllocator const&) = default;

   template <typename U>
   MyAllocator(MyAllocator<U> const&) {}

   pointer address(reference x) const { return &x; }
   const_pointer address(const_reference x) const { return &x; }

   pointer allocate(size_type n, void const* = 0) {
      pointer p = reinterpret_cast<pointer>(malloc(n * sizeof(value_type)));
      std::cout << "allocation of " << n << " elements of " << sizeof(value_type) << " bytes each at " << (void const*)p << "\n";
      return p;
   }

   void deallocate(pointer p, size_type n) {
      std::cout << "deallocation of " <<n << " elements of " << sizeof(value_type) << " bytes each at " << (void const*)p << "\n";
      free(p);
   }

   size_type max_size() const throw() { return std::numeric_limits<size_type>::max() / sizeof(value_type); }

   template <typename U, typename... Args>
   void construct(U* p, Args&&... args) { ::new ((void*)p) U (std::forward<Args>(args)...); }

   template <typename U>
   void destroy(U* p) { p->~U(); }
};

template <typename T>
using MyList = std::list<T, MyAllocator<T>>;

int main() {
   MyList<int> l;
   l.push_back(1);
}

【讨论】:

    猜你喜欢
    • 2012-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-28
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    相关资源
    最近更新 更多