2011-02-08 2 views
1

C++ Скажем, у меня есть некоторые данные, выделенные где-то в моей программе, как:с босыми Приведение типов данных в обертке

some_type a; 

, и я хочу, чтобы обернуть эти данные в классе для доступа. Справедливо ли сказать,

class Foo { 
private: 
    some_type _val; 
public: 
    inline void doSomething() { c_doSomething(&_val); } 
} 

Foo *x = reinterpret_cast<Foo *>(&a); 
x->double(); 

Класс не имеет виртуальные функции, и включает в себя только один элемент данных типа я пытаюсь обернуть. Указывает ли стандарт C++, что этот reinterpret_cast является безопасным и действительным? sizeof(Foo) == sizeof(some_type), проблемы с выравниванием адресов или что-нибудь еще? (В моем случае я был бы уверен, что some_type является либо примитивным типом, например int, либо структурой POD, но мне любопытно, что произойдет, если мы не будем применять это ограничение, например, производный класс a UIWidget как UIMenuItem, или что-то.)

Спасибо!

ответ

2

14882/1998/9.2.17:

«Указатель на объект PODstruct , соответствующим образом преобразованы с использованием reinterpret_cast, указывает на его первоначального элемента (или, если этот член битовое поле, затем к . блок, в котором он находится), и наоборот [Примечание:. Там может поэтому быть неназванной обивка внутри объекта PODstruct , но не в ее начале, по мере необходимости для достижения соответствующего выравнивания]»

Таким образом, было бы действительно, если ваша обертка была строго POD сама по себе. Однако спецификаторы доступа означают, что это не строго POD. Тем не менее, мне было бы интересно узнать, изменяет ли текущая реализация макет объекта из-за спецификаторов доступа. Я думаю, что для всех практических целей вам хорошо идти.

А для случая, когда элемент не является POD, следует, что контейнер не является POD, и, следовательно, все ставки отключены.

+0

Спасибо, это кажется довольно окончательным. –

4

Правомерно сказать ...

Нет, это не действует. Существует только небольшое количество типов, которые можно обрабатывать как a; полный список можно найти in an answer I gave to another question.

Указывает ли стандарт C++, что этот reinterpret_cast является надежным и действительным?

Стандарты на С ++ очень мало говорят о reinterpret_cast. Его поведение почти полностью определяется реализацией, поэтому его использование обычно не переносится.

правильный способ сделать это будет либо

  • имеют Foo конструктор, который принимает some_type аргумент и делает его копию или сохраняет ссылку или указатель на него, или

  • реализует ваш интерфейс «обертки» как набор функций, не являющихся членами, которые принимают объект some_type по ссылке в качестве аргумента.

+0

Я не так хорошо разбираюсь в стандарте, но, просматривая список, который вы дали в этом ответе, я вижу «совокупность или тип объединения, который включает один из вышеупомянутых типов среди его членов (в том числе, рекурсивно, член субагрегата или содержащегося объединения) », который, похоже, может применяться здесь - единственное хранилище, к которому должен быть обращен доступ, должен иметь тот же адрес, что и' a', и он имеет тот же динамический тип, что и 'a', правильно? –

+1

Технически класс не является агрегатом, поскольку он имеет спецификаторы доступа. Это позволит компилятору отказаться от предложений совместимости C и позволяет ему выбирать любой макет для класса. –

+0

@Aidan: Это не тот динамический тип. Динамический тип 'a' -' some_type'. Поскольку 'a' объявлен как объект типа' some_type', его динамический тип и статический тип всегда будут 'some_type'. Динамический тип - это фактический тип объекта. Статический тип - это тип, названный в исходном коде. Единственный раз, когда они могут быть разными, - это когда у вас есть указатели или ссылки (например, в 'Base * p = new Derived;', динамический тип '* p' -' Derived', а статический тип - 'Base'). –

1

Поскольку ваш объект Foo уже действует только до тех пор, как существующая действует:

struct Foo { 
    some_type &base; 

    Foo(some_type &base) : base (base) {} 

    void doSomething() { c_doSomething(&base); } 
} 

//... 
Foo x = a; 
x.doSomething(); 
1

Вы хотите посмотреть правила, регулирующие POD типы (простые старые данные). Если класс C++ является POD-типом, то да, вы можете его отличить.

Сведения о том, что на самом деле происходит и как обрабатывается сглаживание, являются определенными реализациями, но обычно разумны и должны соответствовать тому, что произойдет с похожим типом или структурой C.

Я использую это много в моем проекте, который реализует деревья B + в картах общей памяти. Он работал в GCC на нескольких типах Linux и BSD, включая Mac OS X. Он также отлично работает в Windows с MSVC.

0

Да, это допустимо, если тип обертки, который вы создаете (Foo в вашем примере), является POD-типом.

Смежные вопросы