Namespaces
Variants

Non-static data members

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

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 спецификатор класса хранения не разрешен (но он разрешен для static членов данных);
(since C++11)
  • неполные типы , абстрактные классы и их массивы не допускаются: в частности, класс C не может иметь нестатический член данных типа C , хотя он может иметь нестатический член данных типа C& (ссылка на C) или C* (указатель на C );
  • нестатический член данных не может иметь то же имя, что и имя класса, если присутствует хотя бы один пользовательский конструктор;
(since C++11)

Кроме того, bit-field объявления разрешены.

Содержание

Компоновка

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

Для не- union типов классов, non-zero-sized (since C++20) члены не разделённые access specifier (until C++11) с одинаковым member access (since C++11) всегда размещаются так, что члены, объявленные позже, имеют более высокие адреса в объекте класса. Члены разделённые access specifier (until C++11) с различным управлением доступом (since C++11) размещаются в неуказанном порядке (компилятор может сгруппировать их вместе).

(until C++23)

Для не- union типов классов, non-zero-sized члены всегда размещаются так, что члены, объявленные позже, имеют более высокие адреса в объекте класса. Обратите внимание, что управление доступом членов всё ещё влияет на свойство standard-layout (см. ниже).

(since C++23)

Требования выравнивания могут потребовать заполнения между членами или после последнего члена класса.

Стандартная компоновка

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

(до C++11)

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

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

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

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

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

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

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

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

Инициализация членов класса

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

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

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

#include <iostream>
int x = 0;
struct S
{
    int n = ++x;
    S() {}                 // uses default member initializer
    S(int arg) : n(arg) {} // uses member initializer 
};
int main()
{
    std::cout << x << '\n'; // prints 0
    S s1;                   // default initializer ran
    std::cout << x << '\n'; // prints 1
    S s2(7);                // default initializer did not run
    std::cout << x << '\n'; // prints 1
}

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

(до C++20)

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

struct X
{
    int a[] = {1, 2, 3};  // error
    int b[3] = {1, 2, 3}; // OK
};

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

struct node
{
    node* p = new node; // error: use of implicit or defaulted node::node() 
};

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

struct A
{
    A() = default;     // OK
    A(int v) : v(v) {} // OK
    const int& v = 42; // OK
};
A a1;    // error: ill-formed binding of temporary to reference
A a2(1); // OK (default member initializer ignored because v appears in a constructor)
         // however a2.v is a dangling reference
(начиная с C++11)


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

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

Использование

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

1) Как часть выражения доступа к члену класса, в котором класс либо имеет этот член, либо является производным от класса, который имеет этот член, включая неявные this - > выражения доступа к членам, которые появляются, когда имя нестатического члена используется в любом из контекстов, где this разрешён (внутри тел функций-членов, в списках инициализации членов, во внутриклассовых инициализаторах членов по умолчанию).
struct S
{
    int m;
    int n;
    int x = m;            // OK: implicit this-> allowed in default initializers (C++11)
    S(int i) : m(i), n(m) // OK: implicit this-> allowed in member initializer lists
    {
        this->f();        // explicit member access expression
        f();              // implicit this-> allowed in member function bodies
    }
    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;
    static const std::size_t sz = sizeof m; // OK: m в невычисляемом операнде
};
std::size_t j = sizeof(S::m + 42); // OK: даже несмотря на отсутствие объекта "this" для m
Примечание: такие использования разрешены в соответствии с решением CWG issue 613 в N2253 , которое некоторыми компиляторами (например, clang) рассматривается как изменение в C++11.

Примечания

Макрос тестирования возможностей Значение Стандарт Возможность
__cpp_nsdmi 200809L (C++11) Инициализаторы нестатических членов данных
__cpp_aggregate_nsdmi 201304L (C++14) Агрегатные классы с инициализаторами членов по умолчанию

Отчёты о дефектах

Следующие отчеты об изменениях в поведении, являющиеся дефектными, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение в опубликованной версии Корректное поведение
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
к любому из его базовых классов
CWG 2583 C++11 общая начальная последовательность не
учитывала требования выравнивания
учитываются
CWG 2759 C++20 общая начальная последовательность могла включать
члены, объявленные [[ no_unique_address ]]
они не включаются

Смотрите также

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