Вычисление этого указателя содержащего объекта

0

Является ли следующая портативная и стандартно-совместимая 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;
}
  • 0
    Хорошо, я удалил возможно повторяющийся вопрос. Мой единственный вопрос: "Это соответствует стандартам или нет?" Кстати, голосование за «повторяющиеся вопросы» начинает делать Stackoverflow бесполезным, так как люди, голосующие за закрытие, похоже, не читают того, о чем спрашивали.
  • 1
    Я прочитал то, что спросили;) Тем не менее, теперь я отозвал закрытое голосование, так как редактирование означает, что больше нет реального перекрытия ...
Показать ещё 12 комментариев
Теги:
inner-classes
pointer-arithmetic

1 ответ

3
Лучший ответ
#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 не вообще хорошая идея. Например, с виртуальным наследованием смещения могут широко варьироваться, а не выводиться из информации только статического типа.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню