2011-10-28 59 views
2

我想與本地存儲的成語適用PIMPL方法:便攜式C++對齊?


mytype.h

class mytype { 
struct Impl; 
enum{ storage = 20; } 
char m_storage[ storage ]; 
Impl* PImpl() { return (Impl*)m_storage; } 
public: 
mytype(); 
~mytype(); 
void myMethod(); 
}; 

mytype.cpp

#include "mytype.h" 
struct mytype::Impl { 
int foo; 
void doMethod() { foo = (foo-1)*3; }; 
} 

mytype::mytype() { 
new (PImpl()) Impl(); // placement new 
//check this at compile-time 
static_assert(sizeof(Impl) == mytype::storage); 
//assert alignment? 
} 

mytype::~mytype() { 
PImpl()->~(); 
} 
void mytype::myMethod() { 
PImpl()->doMethod(); 
} 

我唯一關心的是這種方法是m_storage的對齊方式。不保證與int應該以相同的方式對齊。原子能可能有更嚴格的對準要求。我正在尋找比char數組更好的東西來聲明存儲,這使我能夠定義(並斷言)對齊值。你知道這種事嗎?也許增強圖書館已經做到了這一點?

+0

這將不會編譯。數組變量具有名稱右側的大小:'char m_storage [storage];'。 –

+0

謝謝,已經修復了它 – lurscher

回答

4

boost::aligned_storagehttp://www.boost.org/doc/libs/1_43_0/libs/type_traits/doc/html/boost_typetraits/reference/aligned_storage.html應該這樣做。

是不是有一個原因,你不只是使用普通的pimpl方法呢?

+1

我會問這個問題:是否有理由在這種方法中使用普通的pimpl方法?我爲每個對象獲得一個較少的堆分配。並不清楚我丟失了什麼 – lurscher

+2

@lurscher:pimpl成語的意義在於,將來如果您需要添加數據成員,則無需重新編譯所有使用該類的代碼即可。使用你的方法,存儲大小是固定的,所以如果你的實現對象的總大小超過20,它肯定會中斷。通過這樣做,你基本上已經拋棄了pimpl慣用語提供的好處。 –

+0

好的一點。那麼這是一個妥協。儘管如此,除了大小和對齊要求之外,你還是完全不用實現細節*。有時候,這是絕緣和運行時間效率之間完全可以接受的權衡 – lurscher

3

看看boost::aligned_storage。用法很簡單:

#include <boost/aligned_storage.hpp> 
#include <boost/type_traits/alignment_of.hpp> 


typedef boost::aligned_storage<sizeof(ptime), boost::alignment_of<ptime>::value> storage_type; 

using boost::posix_time::ptime; 
storage_type unix_epoch_storage_; 

new (unix_epoch_storage_.address()) ptime(date(1970, 1, 1)); 
3

這裏通常的解決辦法是使用工會要求與您的系統上 最對齊(通常是雙)類型:

static int const requiredStorage = 20; 
union 
{ 
    unsigned char myStorage[requiredStorage]; 
    double dummyForAlignment; 
}; 

如果你不確定使用哪種類型,只需要輸入所有基本的 類型,再加上一些指針(對於數據來說,將其作爲無效函數)來確保。

+0

指向虛擬成員函數的指針並不是您的標準指針。 –

+0

@MooingDuck不,但它也不是硬件類型。通常情況下,它與'struct'的等價物,'struct'具有相同的對齊方式;即最嚴格的成員的對齊。在這種情況下,我傾向於忽視它。 –