struct A { }; // implicitly declared A::operator=
struct B : A {
B& operator=(const B &);
};
B& B::operator=(const B& s) {
this->A::operator=(s); // well formed
return *this;
} — end exampleptr-declarator ( parameter-declaration-clause ) noexcept-specifier attribute-specifier-seq
struct S {
S(); // declares the constructor
};
S::S() { } // defines the constructor
— end example
struct C;
void no_opt(C*);
struct C {
int c;
C() : c(0) { no_opt(this); }
};
const C cobj;
void no_opt(C* cptr) {
int i = cobj.c * 100; // value of cobj.c is unspecified
cptr->c = 1;
cout << cobj.c * 100 // value of cobj.c is unspecified
<< '\n';
}
extern struct D d;
struct D {
D(int a) : a(a), b(d.a) {}
int a, b;
};
D d = D(1); // value of d.b is unspecified
— end example
class X {
public:
X(int);
X(const X&);
X& operator=(const X&);
~X();
};
class Y {
public:
Y(int);
Y(Y&&);
~Y();
};
X f(X);
Y g(Y);
void h() {
X a(1);
X b = f(X(2));
Y c = g(Y(3));
a = f(a);
}
struct S { int mi; const std::pair<int,int>& mp; };
S a { 1, {2,3} };
S* p = new S{ 1, {2,3} }; // Creates dangling reference
— end example
struct S {
S();
S(int);
friend S operator+(const S&, const S&);
~S();
};
S obj1;
const S& cr = S(16)+S(23);
S obj2;
struct X {
operator int();
};
struct Y {
operator X();
};
Y a;
int b = a; // error, a.operator X().operator int() not tried
int c = X(a); // OK: a.operator X().operator int()
— end example
struct X {
operator int();
};
struct Y : X {
operator char();
};
void f(Y& a) {
if (a) { // ill-formed: X::operator int() or Y::operator char()
}
} — end example
struct X {
X(int);
X(const char*, int =0);
X(int, int);
};
void f(X arg) {
X a = 1; // a = X(1)
X b = "Jessie"; // b = X("Jessie",0)
a = 2; // a = X(2)
f(3); // f(X(3))
f({1, 2}); // f(X(1,2))
} — end example
struct Z {
explicit Z();
explicit Z(int);
explicit Z(int, int);
};
Z a; // OK: default-initialization performed
Z b{}; // OK: direct initialization syntax used
Z c = {}; // error: copy-list-initialization
Z a1 = 1; // error: no implicit conversion
Z a3 = Z(1); // OK: direct initialization syntax used
Z a2(1); // OK: direct initialization syntax used
Z* p = new Z(1); // OK: direct initialization syntax used
Z a4 = (Z)1; // OK: explicit cast used
Z a5 = static_cast<Z>(1); // OK: explicit cast used
Z a6 = { 3, 4 }; // error: no implicit conversion
— end exampleconversion-function-id: operator conversion-type-id
conversion-type-id: type-specifier-seq conversion-declarator
conversion-declarator: ptr-operator conversion-declarator
class Y { };
struct Z {
explicit operator Y() const;
};
void h(Z z) {
Y y1(z); // OK: direct-initialization
Y y2 = z; // ill-formed: copy-initialization
Y y3 = (Y)z; // OK: cast notation
}
void g(X a, X b) {
int i = (a) ? 1+a : 0;
int j = (a&&b) ? a+b : i;
if (a) {
}
} — end example&ac.operator int*i; // syntax error: // parsed as: &(ac.operator int *)i // not as: &(ac.operator int)*i
operator int [[noreturn]] (); // error: noreturn attribute applied to a type
— end example
struct S {
operator auto() const { return 10; } // OK
template<class T>
operator auto() const { return 1.2; } // error: conversion function template
}; — end exampleptr-declarator ( parameter-declaration-clause ) noexcept-specifier attribute-specifier-seq
struct B {
virtual ~B() { }
};
struct D : B {
~D() { }
};
D D_object;
typedef B B_alias;
B* B_ptr = &D_object;
void f() {
D_object.B::~B(); // calls B's destructor
B_ptr->~B(); // calls D's destructor
B_ptr->~B_alias(); // calls D's destructor
B_ptr->B_alias::~B(); // calls B's destructor
B_ptr->B_alias::~B_alias(); // calls B's destructor
} — end example
void* operator new(std::size_t, void* p) { return p; }
struct X {
X(int);
~X();
};
void f(X* p);
void g() { // rare, specialized use:
char* buf = new char[sizeof(X)];
X* p = new(buf) X(222); // use buf[] and initialize
f(p);
p->X::~X(); // cleanup
}
class Arena;
struct B {
void* operator new(std::size_t, Arena*);
};
struct D1 : B {
};
Arena* ap;
void foo(int i) {
new (ap) D1; // calls B::operator new(std::size_t, Arena*)
new D1[i]; // calls ::operator new[](std::size_t)
new D1; // ill-formed: ::operator new(std::size_t) hidden
} — end example
class X {
void operator delete(void*);
void operator delete[](void*, std::size_t);
};
class Y {
void operator delete(void*, std::size_t);
void operator delete[](void*);
}; — end example
struct B {
virtual ~B();
void operator delete(void*, std::size_t);
};
struct D : B {
void operator delete(void*);
};
void f() {
B* bp = new D;
delete bp; // 1: uses D::operator delete(void*)
}
Here, storage for the non-array object of class
D
is deallocated by
D::operator delete(),
due to the virtual destructor.
struct B {
virtual ~B();
void operator delete[](void*, std::size_t);
};
struct D : B {
void operator delete[](void*, std::size_t);
};
void f(int i) {
D* dp = new D[i];
delete [] dp; // uses D::operator delete[](void*, std::size_t)
B* bp = new D[i];
delete[] bp; // undefined behavior
}
struct complex {
complex();
complex(double);
complex(double,double);
};
complex sqrt(complex,complex);
complex a(1); // initialize by a call of complex(double)
complex b = a; // initialize by a copy of a
complex c = complex(1,2); // construct complex(1,2) using complex(double,double),
// copy/move it into c
complex d = sqrt(b,c); // call sqrt(complex,complex) and copy/move the result into d
complex e; // initialize by a call of complex()
complex f = 3; // construct complex(3) using complex(double), copy/move it into f
complex g = { 1, 2 }; // initialize by a call of complex(double, double)
— end example
complex v[6] = { 1, complex(1,2), complex(), 2 };
struct X {
int i;
float f;
complex c;
} x = { 99, 88.8, 77.7 };ctor-initializer: : mem-initializer-list
mem-initializer-list: mem-initializer ... mem-initializer-list , mem-initializer ...
mem-initializer: mem-initializer-id ( expression-list ) mem-initializer-id braced-init-list
mem-initializer-id: class-or-decltype identifier
struct A { A(); };
typedef A global_A;
struct B { };
struct C: public A, public B { C(); };
C::C(): global_A() { } // mem-initializer for base A
— end example
struct A { A(); };
struct B: public virtual A { };
struct C: public A, public B { C(); };
C::C(): A() { } // ill-formed: which A?
— end example
struct C {
C( int ) { } // #1: non-delegating constructor
C(): C(42) { } // #2: delegates to #1
C( char c ) : C(42.0) { } // #3: ill-formed due to recursion with #4
C( double d ) : C('a') { } // #4: ill-formed due to recursion with #3
}; — end example
struct B1 { B1(int); /* ... */ };
struct B2 { B2(int); /* ... */ };
struct D : B1, B2 {
D(int);
B1 b;
const int c;
};
D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ }
D d(10); — end example
struct A {
A();
};
struct B {
B(int);
};
struct C {
C() { } // initializes members as follows:
A a; // OK: calls A::A()
const B b; // error: B has no default constructor
int i; // OK: i has indeterminate value
int j = 5; // OK: j has the value 5
}; — end example
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, unfortunately
— end example
struct V {
V();
V(int);
};
struct A : virtual V {
A();
A(int);
};
struct B : virtual V {
B();
B(int);
};
struct C : A, B, virtual V {
C();
C(int);
};
A::A(int i) : V(i) { /* ... */ }
B::B(int i) { /* ... */ }
C::C(int i) { /* ... */ }
V v(1); // use V(int)
A a(2); // use V(int)
B b(3); // use V()
C c(4); // use V()
— end example
class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) { }
};
class A {
public:
A(int);
};
class B : public A {
int j;
public:
int f();
B() : A(f()), // undefined: calls member function but base A not yet initialized
j(f()) { } // well-defined: bases are all initialized
};
class C {
public:
C(int);
};
class D : public B, C {
int i;
public:
D() : C(f()), // undefined: calls member function but base C not yet initialized
i(f()) { } // well-defined: bases are all initialized
}; — end example
template<class... Mixins>
class X : public Mixins... {
public:
X(const Mixins&... mixins) : Mixins(mixins)... { }
}; — end example
struct B1 {
B1(int, ...) { }
};
struct B2 {
B2(double) { }
};
int get();
struct D1 : B1 {
using B1::B1; // inherits B1(int, ...)
int x;
int y = get();
};
void test() {
D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4),
// then d.x is default-initialized (no initialization is performed),
// then d.y is initialized by calling get()
D1 e; // error: D1 has a deleted default constructor
}
struct D2 : B2 {
using B2::B2;
B1 b;
};
D2 f(1.0); // error: B1 has a deleted default constructor
struct W { W(int); };
struct X : virtual W { using W::W; X() = delete; };
struct Y : X { using X::X; };
struct Z : Y, virtual W { using Y::Y; };
Z z(0); // OK: initialization of Y does not invoke default constructor of X
template<class T> struct Log : T {
using T::T; // inherits all constructors from class T
~Log() { std::clog << "Destroying wrapper" << std::endl; }
};
struct A { A(int); };
struct B : A { using A::A; };
struct C1 : B { using B::B; };
struct C2 : B { using B::B; };
struct D1 : C1, C2 {
using C1::C1;
using C2::C2;
};
struct V1 : virtual B { using B::B; };
struct V2 : virtual B { using B::B; };
struct D2 : V1, V2 {
using V1::V1;
using V2::V2;
};
D1 d1(0); // ill-formed: ambiguous
D2 d2(0); // OK: initializes virtual B base class, which initializes the A base class
// then initializes the V1 and V2 base classes as if by a defaulted default constructor
struct M { M(); M(int); };
struct N : M { using M::M; };
struct O : M {};
struct P : N, O { using N::N; using O::O; };
P p(0); // OK: use M(0) to initialize N's base class,
// use M() to initialize O's base class
— end example
struct X { int i; };
struct Y : X { Y(); }; // non-trivial
struct A { int a; };
struct B : public A { int j; Y y; }; // non-trivial
extern B bobj;
B* pb = &bobj; // OK
int* p1 = &bobj.a; // undefined, refers to base class member
int* p2 = &bobj.y.i; // undefined, refers to member's member
A* pa = &bobj; // undefined, upcast to a base class type
B bobj; // definition of bobj
extern X xobj;
int* p3 = &xobj.i; // OK, X is a trivial class
X xobj;
struct W { int j; };
struct X : public virtual W { };
struct Y {
int* p;
X x;
Y() : p(&x.j) { // undefined, x is not yet constructed
}
};
struct A { };
struct B : virtual A { };
struct C : B { };
struct D : virtual A { D(A*); };
struct X { X(A*); };
struct E : C, D, X {
E() : D(this), // undefined: upcast from E* to A* might use path E* → D* → A*
// but D is not constructed
// “D((C*)this)” would be defined: E* → C* is defined because E() has started,
// and C* → A* is defined because C is fully constructed
X(this) {} // defined: upon construction of X, C/B/D/A sublattice is fully constructed
}; — end example
struct V {
virtual void f();
virtual void g();
};
struct A : virtual V {
virtual void f();
};
struct B : virtual V {
virtual void g();
B(V*, A*);
};
struct D : A, B {
virtual void f();
virtual void g();
D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {
f(); // calls V::f, not A::f
g(); // calls B::g, not D::g
v->g(); // v is base of B, the call is well-defined, calls B::g
a->f(); // undefined behavior, a's type not a base of B
} — end example
struct V {
virtual void f();
};
struct A : virtual V { };
struct B : virtual V {
B(V*, A*);
};
struct D : A, B {
D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {
typeid(*this); // type_info for B
typeid(*v); // well-defined: *v has type V, a base of B yields type_info for B
typeid(*a); // undefined behavior: type A not a base of B
dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B results in B*
dynamic_cast<B*>(a); // undefined behavior, a has type A*, A not a base of B
} — end example
struct X {
X(); // default constructor
X(X&); // copy constructor with a non-const parameter
};
const X cx;
X x = cx; // error: X::X(X&) cannot copy cx into x
— end example
struct S {
template<typename T> S(T);
S();
};
S g;
void h() {
S a(g); // does not instantiate the member template to produce S::S<S>(S);
// uses the implicitly declared copy constructor
} — end exampleX::X(const X&)
X::X(X&)
struct X {
X();
X& operator=(X&);
};
const X cx;
X x;
void f() {
x = cx; // error: X::operator=(X&) cannot assign cx into x
} — end exampleX& X::operator=(const X&)
X& X::operator=(X&)
struct S {
int a;
S& operator=(const S&) = default;
};
struct S {
int a;
S& operator=(const S&) = default;
S& operator=(S&&) = default;
}; — end exampleX& X::operator=(X&&);
class Thing {
public:
Thing();
~Thing();
Thing(const Thing&);
};
Thing f() {
Thing t;
return t;
}
Thing t2 = f();
struct A {
void *p;
constexpr A(): p(this) {}
};
constexpr A g() {
A a;
return a;
}
constexpr A a; // well-formed, a.p points to a
constexpr A b = g(); // well-formed, b.p points to b
void g() {
A c = g(); // well-formed, c.p may point to c or to an ephemeral temporary
}
class Thing {
public:
Thing();
~Thing();
Thing(Thing&&);
private:
Thing(const Thing&);
};
Thing f(bool b) {
Thing t;
if (b)
throw t; // OK: Thing(Thing&&) used (or elided) to throw t
return t; // OK: Thing(Thing&&) used (or elided) to return t
}
Thing t2 = f(false); // OK: no extra copy/move performed, t2 constructed by call to f
struct Weird {
Weird();
Weird(Weird&);
};
Weird g() {
Weird w;
return w; // OK: first overload resolution fails, second overload resolution selects Weird(Weird&)
} — end example