Хорошо ли определен адрес члена неинициализированного объекта?

Рассмотрим следующий пример. когда bar построен, это дает его базовый тип (foo) конструктор адрес my_member.y где my_member элемент данных, который еще не был инициализирован

struct foo {
    foo(int * p_x) : x(p_x) {}
    int * x;
};

struct member {
    member(int p_y) : y(p_y) {}
    int y;
};

struct bar : foo
{
    bar() : foo(&my_member.y), my_member(42) {}
    member my_member;
};

#include <iostream>

int main()
{
    bar my_bar;
    std::cout << *my_bar.x;
}

Это хорошо определено? Законно ли брать адрес элемента данных неинициализированного объекта? Я нашел этот вопрос о передаче ссылки на неинициализированный объект, но это не совсем то же самое. В этом случае я использую оператор доступа члена . на неинициализированном объекте.

Это правда, что адрес элемента данных объекта не должен изменяться при инициализации, но это не обязательно делает принятие этого адреса четким. Кроме того, на странице ccpreference.com, посвященной операторам доступа пользователей, есть следующее:

Первый операнд обоих операторов оценивается, даже если в этом нет необходимости (например, когда второй операнд называет статический член).

Я понимаю, что это означает, что в случае &my_member.ymy_member будет оцениваться, что я считаю, хорошо (как int x; x; кажется в порядке) но я не могу найти документацию, подтверждающую это тоже.

2 ответа

Решение

Сначала давайте уточним вопрос.

То, что вы делаете, не использует неинициализированный объект, вы используете объект не в течение срока его службы. my_member построен после fooследовательно, время жизни my_member не началось в foo(&my_member.y),

Из [basic.life]

до того, как началось время жизни объекта, но после того, как хранилище, которое будет занимать объект, было выделено [...], любое значение glvalue, которое относится к исходному объекту, может использоваться, но только ограниченным образом. [...] такое glvalue относится к выделенному хранилищу, и использование свойств glvalue, которые не зависят от его значения, является четко определенным. Программа имеет неопределенное поведение, если:

  • glvalue используется для доступа к объекту, или [...]

Здесь доступ к нему означает специально либо чтение, либо изменение значения объекта.

Оценка my_member возвращает lvalue, и нет ничего, что требовало бы преобразования в prvalue, следовательно, оно остается lvalue. Кроме того, оценка my_member.y это также lvalue. Затем мы заключаем, что к значению объекта не обращались, это хорошо определено.

Да, вы можете пройти &my_member.y в fooконструктор, и даже скопировать указатель - что вы делаете с x(p_x),

Поведение при разыменовании этого указателя, хотя в fooконструктор не определен. (Но вы этого не делаете.)

Другие вопросы по тегам