我使用下面的代码将std::list
与std::forward_list
#include <iostream>
#include <list>
#include <forward_list>
#include <windows.h>
int main()
{
LARGE_INTEGER start_;
LARGE_INTEGER end_;
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
std::list<long long> list;
QueryPerformanceCounter(&start_);
for(long long i=0;i<50000000;i++)
list.push_front(i);
QueryPerformanceCounter(&end_);
std::cout<< (end_.QuadPart - start_.QuadPart) / (freq.QuadPart / 1000) <<"\n";
cin.get();
}
我用forward_list
更改了列表。
并测量两者的时间和大小
结果:
//long long
// size time
//forward list 1157.3 2360
//list 1157.3 2450
我也为此代码做了同样的事情:
int main()
{
LARGE_INTEGER start_;
LARGE_INTEGER end_;
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
std::list<char> list;
QueryPerformanceCounter(&start_);
for(long long i=0;i<50000000;i++)
list.push_front('a');
QueryPerformanceCounter(&end_);
std::cout<< (end_.QuadPart - start_.QuadPart) / (freq.QuadPart / 1000 )<<"\n";
std::cin.get();
}
结果:
//char
// size time
//forward list 773 2185
//list 1157 2400
问题是为什么使用std::forward_list
whith char比使用long std::list
长得多好。
我知道速度几乎相同,但容器的大小呢?
//long long
// size(mb) time
//forward list 1157.3 2360
//list 1157.3 2450
//char
// size(mb) time
//forward list 773 2185
//list 1157 2400
答案 0 :(得分:6)
首先要注意的是,这并不是“好得多”。差异完全是微不足道的。
除此之外,我认为复制8个字节需要比复制一个字节稍长一些;另外,您的常量'a'
不需要读取寄存器/内存,其值可以硬编码到您的可执行文件中。
答案 1 :(得分:3)
forward_list
通常实现为简单的单链表。列表节点具有指向列表中的以下节点的单个指针,以及保存实际用户数据的数据字段。 forward_list<T>
的单个节点的大小将为sizeof(void*) + sizeof(T)
,假设(1)所有数据指针具有相同的大小,并且(2)T
没有更严格的对齐比void*
。
list
实现为双链表。因此,单个节点将具有数据字段和指向下一个和前一个列表节点的指针。因此list<T>
节点的大小为2 * sizeof(void*) + sizeof(T)
,其假设与上述相同。
内存分配器通常在块中分配内存,这些块的大小是最大基本对齐的倍数。在提供分配的粒度和跟踪开销量之间存在权衡。以基本对齐的倍数分配块是一个很好的平衡点,并且还有额外的好处,即确保分配始终与任何未过度对齐的类型正确对齐。
让我们假设您的程序在32位实现上运行 - sizeof(void*) == 4
- 并且系统分配器使用8字节的块大小 - sizeof(double)
。这些假设适用于MS Visual C ++实现的典型32位Windows C ++。根据这些假设,各种对象的大小为:
forward_list<char>
节点:sizeof(void*) + sizeof(char) == 5
,内存分配器将向上舍入为8字节分配。forward_list<long long>
node:sizeof(void*) + sizeof(long long) == 12
,内存分配器将为16字节分配。list<char>
node:2 * sizeof(void*) + sizeof(char) == 9
,内存分配器将为16字节分配。list<long long>
节点:2 * sizeof(void*) + sizeof(long long) == 16
,内存分配器自16以来不会舍入为8的倍数。对于OP中的类型,forward_list<char>
每个元素分配8个字节,list<char>
,list<long long>
和forward_list<long long>
的所有元素分配16个字节。这是对内存使用情况观察的一种可能解释。