Является ли следующая портативная и стандартно-совместимая C++, всегда возвращающая "успех"?
#include <iostream>
#include <cstddef>
struct Containing {
struct {
Containing * get_containing () {
return reinterpret_cast<Containing *> (
(char *) this - offsetof (Containing, inner)
);
}
} inner;
};
int main () {
Containing c;
std::cout
<< (c.inner.get_containing () == &c ? "success" : "fail")
<< std::endl;
}
#include <iostream>
#include <cstddef>
struct Containing {
struct {
Containing * get_containing () {
return reinterpret_cast<Containing *> (
(char *) this - offsetof (Containing, inner)
);
}
} inner;
};
int main () {
Containing c;
std::cout
<< (c.inner.get_containing () == &c ? "success" : "fail")
<< std::endl;
}
Указанный код, который я повторил выше, в порядке, потому что reinterpret_cast
в/из первого элемента POD поддерживается для совместимости C.
Как я помню, C++ 11 расширил набор типов, в которых работает reinterpret_cast
.
Однако, как только вы вводите виртуальную функцию или другие вещи, отличные от POD'', вы превышаете рабочий режим offsetof
, а также гарантируете reinterpret_cast
.
Стандард. Используя функцию "Найти" в моем PDF-читателе, применяемую к документу [N3290.pdf] (окончательный вариант C++ 11, идентичный стандарту), тремя щелчками мыши была предложена следующая информация о offsetof
:
C++ 11 §18.2/4:
"Макросoffsetof
(тип, член-обозначение) принимает ограниченный набор аргументов типа в этом международном стандарте. Если тип не является стандартным классом макета (раздел 9), результаты не определены".
Аналогично, нажав на заголовок раздела 9 "Классы", а затем попросив читателя PDF выполнить поиск reinterpret_cast
, я обнаружил...
C++ 11 9.2/20:
"Указатель на объект структуры стандартного макета, соответствующим образом преобразованный с использованиемreinterpret_cast
, указывает на его начальный член (или если этот элемент является битовым полем, а затем в единицу, в которой он находится) и наоборот"
На практике. Использование offsetof
для первого элемента бит бессмысленно, поскольку оно гарантируется при смещении 0 (без дополнений до). Чтобы сделать эту вещь значимой, вы должны понимать логическое обобщение данного кода, где...
char
). Затем для типов POD или C++ 11 более общий стандартный макет, offsetof
отлично, но reinterpret_cast
нуждается в конкретной поддержке компилятора. С Visual C++ все в порядке. С помощью g++ вам лучше либо, по возможности, отключить его глупые предупреждения и связанные с ними глупые оптимизации, либо сделать обход через указатель void
.
Exeeding пределы offsetof
не вообще хорошая идея. Например, с виртуальным наследованием смещения могут широко варьироваться, а не выводиться из информации только статического типа.