Пространства имён
Варианты
Действия

Нестатические элементы данных

Материал из cppreference.com
< cpp‎ | language
 
 
 
 

Нестатические элементы данных объявляются в спецификации элемента класса.

class S {int n;// нестатический элемент данныхint& r;// нестатический элемент данных ссылочного типаint a[2]={1, 2};// нестатический элемент данных с инициализатором элемента// по умолчанию (C++11)std::string s, *ps;// два нестатических элемента данныхstruct NestedS {std::string s;} d5;// нестатический элемент данных вложенного типаchar bit :2;// двухбитное битовое поле};

Разрешены любые простые объявления, кроме

  • спецификаторы классов памяти extern и register не допускаются;
  • спецификатор класса памяти thread_local не разрешён (но разрешён для статических элементов данных);
(начиная с C++11)
  • неполные типы, типы абстрактных классов и их массивы не допускаются: в частности, класс C не может иметь нестатический элемент данных типа C, хотя он может иметь нестатический элемент данных типа C& (ссылка на C) или C* (указатель на C);
  • нестатический элемент данных не может иметь то же имя, что и имя класса, если присутствует хотя бы один объявленный пользователем конструктор;
(начиная с C++11)

Кроме того, разрешены объявления битовых полей.

Содержание

[править]Компоновка

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

Для типов классов, отличных от union, элементы ненулевого размера(начиная с C++20), не разделённые спецификатором доступа(до C++11), с одинаковым доступом к элементу(начиная с C++11), всегда распределяются таким образом, чтобы элементы, объявленные позже, имели более высокие адреса внутри объекта класса. Элементы, разделённые спецификатором доступа(до C++11), с разным контролем доступа(начиная с C++11) распределяются в неопределенном порядке (компилятор может сгруппировать их вместе). Требования к выравниванию могут потребовать заполнения между элементами или после последнего элемента класса.

(до C++23)

Для типов классов, отличных от union, всегда выделяются элементы ненулевого размера, так что элементы, объявленные позже, имеют более высокие адреса внутри объекта класса. Обратите внимание, что контроль доступа к элементу по-прежнему влияет на свойство стандартной компоновки (смотрите ниже).

(начиная с C++23)

[править]Стандартная компоновка

Класс считается стандартным и имеет свойства, описанные ниже, тогда и только тогда, когда он является классом POD.

(до C++11)

Класс, в котором все нестатические элементы данных имеют одинаковый контроль доступа и выполняются некоторые другие условия, называется классом стандартной компоновки (список требований смотрите в разделе класс со стандартным выравниванием).

(начиная с C++11)

Общая начальная последовательность двух стандартных классовых типов, не являющихся объединением, представляет собой самую длинную последовательность нестатических элементов данных и битовых полей в порядке объявления, начиная с первого такого объекта в каждом из классов, так что

  • либо оба объекта объявлены с атрибутом [[no_unique_address]], либо ни один из них,
(начиная с C++20)
  • соответствующие объекты имеют совместимые по выравниванию типы,
  • соответствующие объекты имеют одинаковые требования к выравниванию, и
  • либо оба объекта являются битовыми полями одинаковой ширины, либо ни один из них не является битовым полем.
struct A {int a;char b;};struct B {constint b1;volatilechar b2;};// общая начальная последовательность A и B это A.a, A.b и B.b1, B.b2struct C {int c;unsigned:0;char b;};// общая начальная последовательность A и C это A.a и C.cstruct D {int d;char b :4;};// общая начальная последовательность A и D это A.a и D.dstruct E {unsignedint e;char b;};// общая начальная последовательность A и E пуста

Два типа класса не объединения со стандартной компоновкой называются совместимыми по компоновке, если они относятся к одному типу, игнорируя cv-квалификаторы, если таковые есть, совместимы по компоновке перечислений (то есть перечисления с одним и тем же базовым типом), или если их общая начальная последовательность состоит из нестатических элементов данных и битовых полей (в приведённом выше примере, A и B совместимы по компоновке)

Два объединения со стандартной компоновкой называются совместимыми-по-компоновке, если они имеют одинаковое количество нестатических элементов данных, а соответствующие нестатические элементы данных (в любом порядке) имеют типы, совместимые с компоновкой.

Стандартные типы компоновок обладают следующими особыми свойствами:

  • В объединении стандартной компоновки с активным элементом типа класса не объединения T1, разрешено читать нестатический элемент данных m другого элемента объединения, не являющегося типом класса объединения T2 при условии, что m является частью общей начальной последовательности T1 и T2 (за исключением того, что чтение volatile элемента через не volatile glvalue не определено).
  • Указатель на объект типа класса стандартной компоновки может быть reinterpret_cast в указатель на его первый нестатический элемент данных, не являющийся битовым полем (если он имеет нестатические элементы данных), или на любой другой подобъект его базового класса (если есть), и наоборот. Другими словами, заполнение не допускается перед первым элементом данных стандартного типа компоновки. Обратите внимание, что правила строгого псевдонима по-прежнему применяются к результату такого приведения.
  • Макрос offsetof может использоваться для определения смещения любого элемента от начала класса стандартной компоновки.

[править]Инициализация элемента

Нестатические элементы данных могут быть инициализированы одним из двух способов:

1) В списке инициализаторов элементов конструктора.
struct S {int n;std::string s; S(): n(7){}// прямая инициализация n, инициализация по умолчанию s   };
2) Через инициализатор элемента по умолчанию, который является фигурными скобками или равен инициализатору, включенному в объявление элемента, и используется, если этот элемент пропущен в списке инициализаторов элементов конструктора.
struct S {int n =7;std::string s{'a', 'b', 'c'}; S(){}// инициализатор элемента по умолчанию будет инициализировать копией n,// инициализировать списком s   };

Если элемент имеет инициализатор элемента по умолчанию и также появляется в списке инициализации элементов в конструкторе, инициализатор элемента по умолчанию игнорируется для этого конструктора.

#include <iostream>   int x =0;struct S {int n =++x; S(){}// использует инициализатор элемента по умолчанию S(int arg): n(arg){}// использует инициализатор элемента};   int main(){std::cout<< x <<'\n';// печатает 0 S s1;// инициализатор по умолчанию выполненstd::cout<< x <<'\n';// печатает 1 S s2(7);// инициализатор по умолчанию не выполненstd::cout<< x <<'\n';// печатает 1}

Инициализаторы элементов по умолчанию не разрешены для элементов битовых полей.

(до C++20)

Элементы типа массива не могут определить свой размер из инициализаторов элементов:

struct X {int a[]={1,2,3};// ошибкаint b[3]={1,2,3};// OK};

Инициализаторам элементов по умолчанию не разрешается вызывать неявное определение заданного по умолчанию конструктора по умолчанию для включающего класса или спецификацию исключения этого конструктора :

struct node { node* p = new node;// ошибка: использование неявного или заданного по умолчанию// node::node()};

Ссылочные элементы не могут быть привязаны к временным элементам в инициализаторе элементов по умолчанию (примечание; то же правило существует для списков инициализаторов элементов):

struct A { A()=default;// OK A(int v): v(v){}// OKconstint& v =42;// OK}; A a1;// ошибка: неверно сформированная привязка временного объекта к ссылке A a2(1);// OK (инициализатор элемента по умолчанию игнорируется, поскольку v появляется// в конструкторе)// однако a2.v это висячая ссылка
(начиная с C++11)

Если элемент ссылка инициализируется из его инициализатора элемента по умолчанию(до C++20)элемент имеет инициализатор элемента по умолчанию(начиная с C++20) и его потенциально оцениваемое подвыражение представляет собой агрегатную инициализацию, которая будет использовать этот инициализатор элемента по умолчанию, программа некорректна:

struct A;extern A a;struct A {const A& a1{ A{a, a}};// OKconst A& a2{ A{}};// ошибка}; A a{a, a};// OK
(начиная с C++17)

[править]Применение

Имя нестатического элемента данных или нестатической функции элемента может появляться только в следующих трёх ситуациях:

1) Как часть выражения доступа к элементу класса, в котором класс либо имеет этот элемент, либо является производным от класса, имеющего этот элемент, включая неявные выражения доступа к элементу this->, которые появляются, когда имя нестатического элемента используется в любом из контекстов, где this разрешён (внутри тел функций-элементов, в списках инициализаторов элементов, в инициализаторах элементов по умолчанию внутри класса).
struct S {int m;int n;int x = m;// OK: неявный this-> разрешён в инициализаторах// по умолчанию (C++11) S(int i): m(i), n(m)// OK: неявный this-> разрешён в списках// инициализаторов элементов{ this->f();// явное выражение доступа к элементу f();// неявный this-> разрешён в телах функций-элементов}void f();};
2) Чтобы сформировать указатель на нестатический элемент.
struct S {int m;void f();};int S::*p =&S::m;// OK: использование m для создания указателя на элементvoid(S::*fp)()=&S::f;// OK: использование f для создания указателя на элемент
3) (только для элементов данных, не функций-элементов) При использовании в неполных операндах.
struct S {int m;staticconststd::size_t sz = sizeof m;// OK: m в неполном операнде};   std::size_t j = sizeof(S::m+42);// OK: хотя для m не существует объекта "this"
Примечания: такое использование разрешено посредством решения CWG проблема 613 в N2253, которая рассматривается некоторыми компиляторами как изменение в C++11 (например clang).

[править]Примечание

Макрос тест функциональностиЗначениеСтандартКомментарий
__cpp_nsdmi200809L(C++11)Инициализаторы нестатических элементов данных
__cpp_aggregate_nsdmi201304L(C++14)Агрегатные классы с инициализаторами элементов по умолчанию

[править]Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 80 C++98 все элементы данных не могут иметь то же имя
, что и имя класса (нарушает совместимость с C)
разрешено нестатическим элементам данных совместно использовать
имя класса, если нет объявленного пользователем конструктора
CWG 190 C++98 при определении совместимости компоновки
учитывались все элементы
рассматриваются только нестатические элементы данных
CWG 613 C++98 неполное использование нестатических элементов
данных не допускается
такое использование разрешено
CWG 645 C++98 не было указано, совместимы ли с выравниванием
элементы битового поля и не битового поля
не совместимое выравнивание
CWG 1397 C++11 класс считался завершённым в инициализаторах
элементов по умолчанию
инициализация элемента по умолчанию не может
вызвать определение конструктора по умолчанию
CWG 1425 C++98 было неясно, имеет ли объект со стандартным
выравниванием тот же адрес, что и первый
нестатический элемент данных или первый подобъект
базового класса
нестатический элемент данных, если он присутствует,
в противном случае подобъект базового класса, если он присутствует
CWG 1696 C++98 ссылочные элементы могут быть инициализированы
временными определениями (время жизни которых
закончится в конце конструктора)
такая инициализация не корректна
CWG 1719 C++98 не так cv-квалифицированные типы не были совместимы
с компоновкой
cv-квалификация игнорируется,
спецификация улучшена
CWG 2254 C++11 указатель на класс со стандартной компоновкой
без элементов данных может быть reinterpret_cast
в его первый базовый класс
может быть reinterpret_cast в любой из его
базовых классов

[править]Смотрите также

классы
статические элементы
нестатические функции-элементы
проверяет, является ли тип типом со стандартной компоновкой
(шаблон класса)[править]
смещение в байтах от начала типа со стандартной компоновкой до указанного элемента
(функция-макрос)[править]
close