2014-02-23 45 views
7

問題如何在編譯時計算C++ 11中的struct padding?

我有一個極大的一個std ::矢量Foo的

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

我都可以一次性使用fwrite的連續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; 
}; 
+5

你*可以*只是在填充其他字段之前使用memset清除整個結構。一般來說,你的結構也可以在成員之間填充,valgrind會(或者至少應該)同樣地抱怨,並且在最後添加填充成員不會解決這個問題。 – hvd

+0

@ hvd我喜歡你的建議 - 我可以創建一個類模板,它在構造函數中作爲參數Foo和memset。這樣,Foo仍然可以以正常方式初始化。我會試試這個,如果沒有問題,更新OP。謝謝。 – kfmfe04

+0

注意:如果您從基類派生,則允許編譯器將派生類成員存儲在基類padding中。 –

回答

0

不當然,如果我理解得很好,那又怎麼樣:

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; 
+4

這不起作用:'sizeof(T)'報告*填充的*大小。 –

3

那麼,我可以看到兩種方式:

  1. 使用你的類的unionchar大如類
  2. 使用模板類和元編程找出所有的墊襯
  3. 數組

不用多說前似乎容易得多,所以在這裏你可以:

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