переносимое выравнивание c ++? - PullRequest
2 голосов
/ 28 октября 2011

Я хочу применить идиому Pimpl с идиомой локального хранилища:


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. char не гарантируется выравнивание так же, как должно быть int. Атомика может иметь еще более строгие требования к выравниванию. Я ищу что-то лучше, чем массив char для объявления хранилища, которое дает мне возможность также определять (и утверждать) значения выравнивания. Вы знаете что-нибудь подобное? может быть, библиотека повышения уже делает это?

Ответы [ 3 ]

4 голосов
/ 28 октября 2011

boost::aligned_storage http://www.boost.org/doc/libs/1_43_0/libs/type_traits/doc/html/boost_typetraits/reference/aligned_storage.html должны добиться цели.

Есть ли причина, по которой вы не просто используете обычный подход pimpl?

3 голосов
/ 28 октября 2011

Обычное решение здесь - использовать объединение с типом, требующим наибольшее выравнивание в вашей системе (обычно двойное):

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

Если вы не уверены, какой тип использовать, просто добавьте все основные типы, плюс несколько указателей (на данные, для аннулирования, на функцию), чтобы быть уверенным.

3 голосов
/ 28 октября 2011

Взгляните на 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));
...