【问题标题】:Node size for unordered_map bucketsunordered_map 存储桶的节点大小
【发布时间】:2019-01-08 20:08:36
【问题描述】:

我有一个程序,我想在其中存储 kmers(大小为 k 的子字符串)和它们出现的次数。对于这个特定的应用程序,我正在读取具有这些值的文件,如果它们出现的次数 > 255,则可以向下舍入到 255。我认为如果我将键值对存储为(字符串, unsigned char) 与将键值对存储为 (string, int) 相比可能会节省空间,但是当我通过运行 /usr/bin/time 检查最大驻留大小时,情况似乎并非如此。

为了确认,我还尝试运行以下测试程序,其中我在 unordered_map 中交替了值的类型:

#include <iostream>
#include <unordered_map>
#include <utility>
#include <string>
#include <fstream>

int main() {
    std::unordered_map<std::string, unsigned char> kmap;
    std::ifstream infile("kmers_from_reads");
    std::string kmer;
    int abun;

    while(infile >> kmer >> abun) {
        unsigned char abundance = (abun > 255) ? 255 : abun;
        kmap[kmer] = abundance;
    }

    std::cout << sizeof(*kmap.begin(0)) << std::endl; 
}

这似乎不会影响存储桶中节点的大小(在我的机器上,它对于 unsigned char 和 int 值都返回 40)。

我想知道每个桶中节点的大小是如何确定的。

我对无序映射的理解是,c++ 标准或多或少需要单独的链接,并且桶中的每个节点必须至少有一个指针,以便元素是可迭代的并且可以被擦除(http://bannalia.blogspot.com/2013/10/implementation-of-c-unordered.html)。但是,我不明白存储值的空间量是如何确定的,而且它似乎也必须灵活地容纳更大的值。我还尝试查看 gcc libstc++ unordered_map 标头 (https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/unordered_map.h),但很难理解发生了什么。

【问题讨论】:

    标签: c++ unordered-map memory-alignment


    【解决方案1】:

    编译并执行这段代码:

    #include <iostream>
    #include <unordered_map>
    #include <utility>
    #include <string>
    #include <fstream>
    
    class foo
    {
       std::string kmer;
       unsigned char abun;
    };
    
    class bar
    {
        std::string kmer;
        int abun;
    };
    
    int main() {
        std::cout << sizeof(foo) << " " << sizeof(bar) << std::endl;
    }
    

    我明白了,你可能也会,40 40。这是因为对齐要求。例如,如果std::string 包含至少一个指针(它几乎肯定会这样做),则它必须在至少 4 字节的边界上对齐。

    想象一下,如果sizeof(foo) 是 39,而你的代码是 foo foos[2]。如果foos[0].kmer 中的指针正确对齐,foos[1].kmer 中的指针就不会对齐。那将是一场灾难。

    【讨论】:

    • 嗨,大卫,感谢您的回答。我一直在考虑这个问题,我还有几个问题。
    • 问题 1 - 那么任何类的大小将取决于其最大成员的对齐要求?问题 2 - 我检查了一个只有一个指针的类的大小,它是 8。所以实际上这意味着它们必须在 8 字节边界而不是 4 字节边界上对齐,对吗?
    • 1) 严格来说,其对齐要求最大的成员的对齐要求。对齐要求并不总是与大小相同。 2) 可能。我们可以想象一个具有 8 字节指针的平台,只要求它们在 4 字节边界上对齐。重要的一点是类型实际上有两种尺寸。您可以通过查看像 struct foo { char m1; int* m2; } 这样的结构的大小来进行测试。它填充的字节数将告诉您m2 的对齐要求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 2017-05-12
    • 1970-01-01
    • 1970-01-01
    • 2018-02-24
    相关资源
    最近更新 更多