【问题标题】:Different size of unordered_map across gcc versions跨 gcc 版本的 unordered_map 大小不同
【发布时间】:2016-12-20 09:33:00
【问题描述】:

sizeof(std::unordered_map<int, int>)的值在linux上gcc 4.6—4.9左右的不同gcc版本中似乎有所不同:

  • 4.6: 56
  • 4.7: 64
  • 4.8:48
  • 4.9 及更高版本:56

(test code on coliru)(其他专业同理)

当将使用不同 gcc 版本编译的库链接在一起时,这显然会导致内存访问问题。

也就是说,我现在面临的一个问题是一个库,比如libfoo,它公开了一些class Foo 作为它的接口。即库提供foo.h头文件:

class Foo {
    std::unordered_map<int, int> map;
    int val;
public:
    Foo(): val(42) {}
    int getVal(); 
};

还提供编译库libfoo.so,其中包含访问Foo::val 的Foo::getVal() 的二进制代码。该库是使用 gcc 4.6 编译的,因此假定 val 与 Foo start 有 56 个字节的偏移量。

现在我编写使用libfoo 的程序。我写

#include <foo.h>    
int bar() {
    Foo foo;
    return foo.getVal();
}

我使用 gcc 4.8 构建我的程序。它假定unordered_map 的大小为48 字节,因此只为Foo 对象分配48+sizeof(int)。结果,foo.getVal() 访问对象外部的数据。


所以,我的问题是:

  1. 有没有办法解决这个问题?例如,让 gcc 4.8 使用 gcc 4.6 中的unordered_map?事实上,问题只是分配了适当的内存大小,因为map 字段的所有实际工作只发生在libfoo.so 内部。我认为我可以通过显式分配更多内存并进行新放置来做一些原始指针魔术,但这似乎真的不可靠并且容易出现内存泄漏。
  2. 我说这是一种不常见的情况是对的吗,可能是因为 unordered_map 实现在 gcc
  3. 如果不是,那么一般应如何缓解此类问题?

请注意,链接到特定版本的 libstdc++ 似乎不是问题;问题是计算应该分配多少内存。

【问题讨论】:

    标签: c++ c++11 gcc


    【解决方案1】:

    关于问题1:

    我会使用以下包装器:

    constexpr int DesirableFooSize = 60;
    constexpr bool FooTooSmall = sizeof(Foo) < DesirableFooSize;
    
    class FooWrapper final : private Foo {
        std::enable_if<FooTooSmall, std::array<int8_t, DesirableFooSize - sizeof(Foo)>>::type x;
    public:
        using Foo::getInt;
        using Foo::Foo;
        Foo* getFooPointer() {
            return this;
        }
        Foo& getFooReference() {
            return *this;
        }
    };
    

    并且你程序中的所有代码都应该使用FooWrapper 而不是简单的Foo。这将保证您始终为每个Foo 对象准确分配 60 个字节,永远不要忘记释放这些额外的内存,并且无法访问额外的内存。 Private 继承和显式转换函数特意写在这里,让您在想将 FooWrapper 转换为 Foo 或使用指针或引用做某事时三思而后行。

    【讨论】:

      猜你喜欢
      • 2023-04-01
      • 1970-01-01
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-20
      • 2011-07-17
      相关资源
      最近更新 更多