C++ 如何在c++;11在编译时?

C++ 如何在c++;11在编译时?,c++,c++11,sizeof,C++,C++11,Sizeof,问题 我有一个无数个Foo的std::向量 struct Foo { int m_i; char m_c; char m_padding[3]; // want to replace this }; 我可以一次快速地以二进制形式编写这段连续的Foo 我的问题是,如果我不显式地输入m_填充,计算它,然后自己清除它,valgrind会抱怨未初始化的写入 问题 是否可以在C++11中编写一个模板类,在编译时为我计算填充 如果是这样,我可以将其添加到我所有的Foo的末尾,并自动

问题

我有一个无数个Foo的std::向量

struct Foo
{
  int   m_i;
  char  m_c;
  char  m_padding[3];   // want to replace this
};
我可以一次快速地以二进制形式编写这段连续的Foo

我的问题是,如果我不显式地输入m_填充,计算它,然后自己清除它,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;
};
模板
结构BZero
{
BZero(){std::memset(this,0,sizeof(T));}
};
结构Foo:public BZero
{
国际货币基金组织;
charm_c;
};

我不确定自己是否理解得很好,那么这个呢:

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;
structfoobase{
int i;
字符c;
};
模板
填充结构:公共T{
炭垫[总尺寸(T)];
};
typedef加垫Foo;

我可以看到两种方法:

  • 使用类的
    联合体和与类一样大的
    字符数组
  • 使用模板类和元编程来计算所有填充
  • 不用说,前者似乎容易得多,所以你来:

    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
    
    模板
    类零类{
    公众:
    模板
    ZeroedClass(Args&&…Args){
    新的(&u.t)t(标准:正向(args)…);
    }
    //还需要其他特别成员吗
    ~ZeroedClass(){{uu.t.~t();}
    //访问者
    T&access(){return}.T;}
    T const&get()const{return}
    私人:
    联合大学{
    U(){memset(this,0,sizeof(T));}
    字符缓冲区[sizeof(T)];
    T;
    } _;
    }; // 类零类
    
    在填充其他字段之前,您可以使用
    memset
    清除整个结构。一般来说,您的结构可能在成员之间也有填充,valgrind会(或至少应该)同样抱怨这一点,并且在末尾添加填充成员并不能解决这个问题。@hvd我喜欢您的建议-我可以创建一个类模板,该模板在该构造函数中作为参数Foo和memset。这样,Foo仍然可以以正常方式初始化。我会尝试一下,如果效果好,我会更新OP。注意:如果您从基类派生,则允许编译器将派生类成员隐藏在基类填充中。@MatthieuM。出于好奇:您知道有任何编译器实际执行此优化吗?@pmr
    struct S1{int a;char b;~S1(){};结构S2:S1{char c;};int main(){return sizeof(S2)-sizeof(S1);}
    在我的系统(32位模式和64位模式下的x64 Linux)上返回0。但是由于我不知道的原因,如果析构函数被移除,它不会发生在我的系统上。