sizeof(std :: list <t>)可以因不同类型的T?</t>而有所不同

时间:2012-08-03 11:03:34

标签: c++ stl

我可以假设对于任何类型T,类型std::list<T>将具有相同的常量大小吗?为了说清楚,我的意思是'main'类型本身的大小,而不是它分配的内存。

假设T本身的大小应该只影响使用分配器分配的列表节点的大小,这似乎是合乎逻辑的。

然而,有两件事可能导致我能想到sizeof(std::list<T>)的变量:

  1. 标准C ++库,试图通过将std::list个实例放入T本身来“优化”std::list<T>类型。这对我来说似乎是一个坏主意,它可能打破了标准所要求的“恒定时间”要求;
  2. 标准C ++,对某些类型具有std::list<T>的库专精,其特殊化的大小不同。
  3. 我想不出(1)或(2)的任何用途,但我可能错了。

    我正在考虑实现的是在内部使用std::list<T>为模板类使用固定大小的切片分配器。


    注意:这是针对不同类型的T而不是的不同分配器的差异。我将明确控制所有实例化,并且它们都将使用std::allocator

3 个答案:

答案 0 :(得分:8)

,它可以。

据我所知,标准对list<T>对象的大小没有任何保证。不过,还有其他保证。


让我们揭穿一些事情:

  

标准C ++库试图通过将std::list个实例放入T本身来“优化”std::list<T>类型。这对我来说似乎是一个坏主意,它可能会打破标准所要求的“恒定时间”要求;

只要该数字有界,它就不会以任何方式打破“恒定时间”要求,因为O(5)是O(1)。但是,在splice操作期间,节点应从一个列表移动到另一个列表而不移入内存。因此禁止本地存储。

  

对于某些类型具有std::list<T>库专业化的标准C ++,其特殊化具有不同的大小。

由于我们已经排除了本地存储的可能性,因此很难想象基本std::list<T>类型的任何其他变体本身


让我们担心重要的事情:

std::list<T>分配的内存由其第二个模板参数提供:分配器。大多数分配器(包括默认的std::allocator<T>)使用简单的指针类型:T* ...但是分配器应该随意更改此类型。

因此,通过更改allocator参数(更确切地说,它的指针类型),在我看到的所有实现中,自然会改变std::list容器的大小。

请注意,分配器本身可以专门用于某些类型,但是使用重新绑定魔法会更难实现。

答案 1 :(得分:4)

C ++ 11标准(容器)的第23章没有说明它们的大小,所以从技术上讲,你不能假设它的大小是恒定的。实现者(理论上)可以以影响其足迹的方式为特定基元专门化一些容器。

在实践中,您可以使用sizeof(list<T>) == sizeof(list<int>)并使用sizeof(list<int>)作为“固定”大小的静态断言。最糟糕的事情是编译时错误。

答案 2 :(得分:0)

使用std::list<T>的类的固定大小切片分配器没有多大意义,除非您还为列表本身使用固定大小的切片分配器,列表项可能会比列表标题分配更多。

现在,您当然可以使用第二个模板参数(分配器)为列表提供自己的固定大小的片分配器。但是有一个转折:你不知道切片应该有多大。 list<T>接受allocator<T>,但真正需要的是allocator<U>,其中U是包含prev / next指针和T的结构。为了得到它,它调用方法rebind,签名为template <typename T> template <typename T> allocator<U> allocator<T>::rebind<U>()

由于我实际上需要这样做一次,我所做的就是创建一个对象,它包含多个切片大小的分配器集合。分配器本身比持有一个共享指针和一个指向分配器的共享指针,用于它的参数大小。在重新绑定时,我从集合中提取了适当的分配器,或者如果它不存在则创建一个。如果这样做,它将作为副作用解决列表的分配,因为如果有多个大小,它将为每个创建单独的池。而且它不会有很多不同的尺寸,因为物体不会很大。

相关问题