Non-static data members are the variables that are declared in a member specification of a class.
class S { int n; // non-static data member int& r; // non-static data member of reference type int a[10] = {1,2}; // non-static data member with initializer (C++11) std::string s, *ps; // two non-static data members struct NestedS { std::string s; } d5, *d6; // two non-static data members of nested type char bit : 2; // two-bit bitfield };
Any simple declarations are allowed, except.
-
extern
andregister
storage class specifiers are not allowed; -
thread_local
storage class specifier is not allowed (but it is allowed for static data members); - incomplete types are not allowed: in particular, a class
C
cannot have a non-static data member of typeC
, although it can have a non-static data member of typeC&
(reference to C) orC*
(pointer to C); - a non-static data member cannot have the same name as the name of the class if at least one user-declared constructor is present.
In addition, bit field declarations are allowed.
Non-static data members are allowed to have the same name as the name of the enclosing class unless the class has a user-declared constructor.
Layout
When an object of some class C
is created, each non-static data member of non-reference type is allocated in some part of the object representation of C
. Whether reference members occupy any storage is implementation-defined, but their storage duration is the same as that of the object in which they are members.
For non-union class types, members with the same member access are always allocated so that the members declared later have higher addresses within a class object. Members with different access control are allocated in unspecified order (the compiler may group them together). Alignment requirements may necessitate padding between members, or after the last member of a class.
Standard layout
A class where all non-static data members have the same access control and certain other conditions are satisfied is known as standard layout type (see StandardLayoutType
for the list of requirements).
Two standard-layout non-union class types may have a common initial sequence of non-static data members and bit-fields (since C++14), for a sequence of one or more initial members (in order of declaration), if the members have layout-compatible types and if they are bit-fields, they have the same width (since C++14).
struct A { int a; char b; }; struct B { const int b1; volatile char b2; }; // A and B's common initial sequence is A.a, A.b and B.b1, B.b2 struct C { int c; unsigned : 0; char b; }; // A and C's common initial sequence is A.a and C.c struct D { int d; char b : 4; }; // A and D's common initial sequence is A.a and D.d struct E { unsigned int e; char b; }; // A and E's common initial sequence is empty
Two standard-layout non-union class types are called layout-compatible if they are the same type ignoring cv-qualifiers, if any (since C++14), are layout-compatible enumerations, or if their common initial sequence consists of every non-static data member and bit field (since C++14) (in the example above, A
and B
are layout-compatible).
Two standard-layout unions are called layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in any order) have layout-compatible types.
Standard layout types have the following special properties:
| (until C++14) |
| (since C++14) |
- A pointer to an object of standard-layout struct type can be reinterpret_cast to pointer to its first non-static data member (if it has non-static data members) or otherwise its first base class subobject (if it has any), and vice versa. (padding is not allowed before the first data member). Note that strict aliasing rules still apply to the result of such cast.
- The macro
offsetof
may be used to determine the offset of any member from the beginning of a standard-layout struct
Member initialization
Non-static data members may be initialized in one of two ways:
struct S { int n; std::string s; S() : n(7) // direct-initializes n, default-initializes s { } };
2) Through a default member initializer, which is simply a brace or equals initializer included in the member declaration, which is used if the member is omitted in the member initializer list struct S { int n = 7; std::string s{'a', 'b', 'c'}; S() // copy-initializes n, list-initializes s { } }; If a member has a default member initializer and also appears in the member initialization list in a constructor, the default member initializer is ignored. #include <iostream> int x = 0; struct S { int n = ++x; S() {} // uses default member initializer S(int arg) : n(arg) {} // uses member initializer list }; int main() { std::cout << x << '\n'; // prints 0 S s1; std::cout << x << '\n'; // prints 1 S s2(7); std::cout << x << '\n'; // prints 1 } Default member initializers are not allowed for bit field members. | (since C++11) |
Reference members cannot be bound to temporaries in a default member initializer. 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 Reference members cannot be initialized with a default member initializer if it has a subexpression that would execute aggregate initialization which would use the same initializer: struct A; extern A a; struct A { const A& a1 { A{a,a} }; // OK const A& a2 { A{} }; // error }; A a{a,a}; // OK | (since C++14) |
Usage
The name of a non-static data member or a non-static member function can only appear in the following three situations:
this->
member access expressions that appear when a non-static member name is used in any of the contexts where this is allowed (inside member function bodies, in member initializer lists, in the in-class default member initializers) struct S { int m; int n; int x = m; // OK: implicit this allowed in default initializers (C++11) S(int init) : m(init), n(m) // OK:implicit this allowed in member initializer lists { this->f(); // explicit member access expression f(); // implicit this allowed in member functions } void f(); };
struct S { int m; void f(); }; int S::*p = &S::m; // OK, use of m to make a pointer to member void (S::*fp)() = &S::f; // OK, use of f to make a pointer to member
3) in unevaluated operands struct S { int m; static const std::size_t sz = sizeof m; // OK, m in unevaluated operand }; std::size_t j = sizeof(S::m + 42); // OK, even though there is no "this" object for m | (since C++03) |
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 613 | C++03 | unevaluated uses of non-static data members not allowed | such uses are allowed |
CWG 1696 | C++14 | reference members could be initialized to temporaries (whose lifetime would end at the end of ctor) | such init is ill-formed |
CWG 1719 | C++14 | differently cv-qualified types weren't layout-compatible | cv-quals ignored, spec improved |
See also
- classes
- static data members
- member functions
-
std::is_standard_layout
-
offsetof
Please login to continue.