【问题标题】:How to calculate struct padding in c++11 during compile time?如何在编译期间计算 c++11 中的结构填充?
【发布时间】:2014-02-23 14:24:02
【问题描述】:

问题

我有一个巨大的 Foo 的 std::vector

struct Foo
{
  int   m_i;
  char  m_c;
  char  m_padding[3];   // want to replace this
};

我可以一次将这块连续的 Foo 快速写入二进制形式。

我的问题是,如果我不明确输入那个 m_padding、计算它并自己清除它,valgrind 会抱怨未初始化的写入。

问题

是否可以在 C++11 中编写一个模板类来在编译期间为我计算填充?

如果是这样,我可以将它添加到我所有 Foo 的末尾并自动初始化/清除它们,而不会受到 valgrind 的投诉。

我可以通过计算 sizeof( padding ) = sizeof( Foo ) - sum( sizeof(parts )) 手动完成,但最好为这个计算创建某种类,因为所有信息都可以在编译时获得-时间。

为简单起见,假设 Foo 具有微不足道的布局(type_traits 是一个重要但切题的问题)。另外,请忽略订购问题/跨平台问题。

可能的方法

这并没有直接回答我原来的问题,但 hvd 的建议暗示了一种更简单的方法,似乎适用于我尝试过的一些简单测试用例:

template<typename T>
struct BZero
{
  BZero() { std::memset( this, 0, sizeof( T )); }
};

struct Foo : public BZero<Foo>
{
  int   m_i;
  char  m_c;
};

【问题讨论】:

  • 可以在填写其他字段之前使用memset 清除整个结构。一般来说,你的结构可能在成员之间也有填充,valgrind 会(或至少应该)同样抱怨,并且在最后添加一个填充成员不会解决这个问题。
  • @hvd 我喜欢你的建议——我可以创建一个类模板,在该构造函数中将 Foo 和 memset 作为参数。这样,Foo 仍然可以以正常方式初始化。如果一切正常,我会尝试一下并更新 OP。谢谢。
  • 注意:如果您从基类派生,编译器可以将派生类成员隐藏在基类填充中。
  • @MatthieuM。出于好奇:您知道实际执行此优化的任何编译器吗?
  • @pmr struct S1 { int a; char b; ~S1() {} }; struct S2 : S1 { char c; }; int main() { return sizeof(S2) - sizeof(S1); } 在我的系统上返回 0(x64 Linux,在 32 位模式和 64 位模式下)。但是由于我不知道的原因,如果删除了析构函数,它就不会在我的系统上发生。

标签: c++ c++11 sizeof


【解决方案1】:

嗯,我可以看到两种方式:

  1. 使用您班级的union 和与班级一样大的char 数组
  2. 使用模板类和元编程来计算所有填充

不用说前者似乎更容易,所以你开始吧:

template <typename T>
class ZeroedClass {
public:
    template <typename... Args>
    ZeroedClass(Args&&... args) {
        new (&_.t) T(std::forward<Args>(args)...);
    }

    // Need other special members as well

    ~ZeroedClass() { _.t.~T(); }

    // Accessors
    T& access() { return _.t; }
    T const& get() const { return _.t; }

private:
    union U {
        U() { memset(this, 0, sizeof(T)); }

        char buffer[sizeof(T)];
        T t;
    } _;
}; // class ZeroedClass

【讨论】:

    【解决方案2】:

    不知道我是否理解得很好,这个呢:

    struct FooBase {
        int i;
        char c;
    };
    
    template<typename T, size_t total>
    struct padded : public T {
        char pad[total-sizeof(T)];
    };
    
    typedef padded<FooBase, 8> Foo;
    

    【讨论】:

      猜你喜欢
      • 2015-04-25
      • 2020-11-27
      • 2012-08-19
      • 2014-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-30
      • 2023-04-03
      相关资源
      最近更新 更多