基础概念

定义和 ODR(one definition rule)

ODR: 一个翻译单元中只有一个定义 It consists of the contents of a single source file, plus the contents of any header files directly or indirectly included by it, minus those lines that were ignored using conditional preprocessing statements. A single translation unit can be compiled into an object file, library, or executable program.

注释

注释在预处理之前去除

对象

The following entities are not objects: value, reference, function, enumerator, type, non-static class member, template, class or function template specialization, namespace, parameter pack, and this.

For any two non-bit-field objects with overlapping lifetimes:

  • If any of the following conditions is satisfied, they may have the same address: One of them is nested within the other. Any of them is a subobject of zero size, and their types are not similar. They are both potentially non-unique objects.
  • Otherwise, they always have distinct addresses and occupy disjoint bytes of storage.

An object is a potentially non-unique object if it one of the following objects:

  • A string literal object. 关于字面量的存储问题 If you do not use malloc or new, then the char* or string will be created on the stack or as a compile-time constant.

    void fun() {
    auto s = "123";
    cout << "func s addr:"<<&s << endl;
    cout << "func s value:"<<static_cast<const void*>(s) << endl;
    }
    int main() {
    auto s = "123";
    cout<<"s addr:"<<&s<<endl;
    cout<<"s value:"<<static_cast<const void*>(s)<<endl;
    auto s1 = "123";
    /*
    但是单个字符并不会分配同一地址
    static const char test1 = 'x';
    static const char test2 = 'x';
    const bool b = &test1 != &test2; // always true
    */
    cout << "s1 addr:"<<&s1 << endl;
    cout<<"s1 value:"<<static_cast<const void*>(s1)<<endl;
    cout <<"123 addr:"<< &"123" << endl;
    fun();
    }
    /*
    s addr:0x7ff7bf1f49f8
    s value:0x100d0def0
    s1 addr:0x7ff7bf1f49f0
    s1 value:0x100d0def0
    123 addr:0x100d0def0
    func s addr:0x7ff7bf1f49d8
    func s value:0x100d0def0
    */
  • The backing array of an initializer list.

  • A subobject of a potentially non-unique object.

范围

The locus of a name declared in a simple declaration is immediately after that name's declarator and before its initializer, if any.

int x = 32; // outer x is in scope
{
int x = x;
// inner x is in scope before the initializer (= x); this does not initialize inner x with the value of outer x (32); this initializes inner x with its own (indeterminate) value
}

std::function<int(int)> f = [&](int n){ return n > 1 ? n * f(n - 1) : n; };
// the name of the function f is in scope in the lambda and can
// be correctly captured by reference, giving a recursive function

const int x = 2; // outer x is in scope
{
int x[x] = {}; // inner x is in scope before the initializer (= {}),
// but after the declarator (x[x])
// in the declarator, outer x is still in scope
// this declares an array of 2 int
}

生命周期

一个对象的声明周期开始: 被分配存储空间的时刻 结束: 销毁(destroy 或析构); 空间释放 对象的生命周期<=其存储的存在

引用的声明周期从初始化开始, 和标量一样结束 (如果被引用的对象先于引用结束, 则产生 dangling 引用)

Temporary objects are created in the following situations:

  • binding a reference to a prvalue
  • initializing an object of type std::initializer_list from a braced-init-list
  • returning a prvalue from a function
  • conversion that creates a prvalue (including T(a, b, c) and T{})
  • lambda expression
  • copy-initialization that requires conversion of the initializer,
  • reference-initialization to a different but convertible type or to a bitfield.
  • when throwing an exception

There are the following exceptions from that:

  • The lifetime of a temporary object may be extended by binding to a reference
  • 当用于初始化或复制数组元素的默认或复制构造函数在评估其默认参数时创建的临时对象,其生命周期会在数组下一个元素开始初始化之前结束。

name lookup

A qualified name is a name that appears on the right hand side of the scope resolution operator ::

#include <iostream>
int main()
{
struct std {};
std::cout << "fail\n"; // Error: unqualified lookup for 'std' finds the struct
::std::cout << "ok\n"; // OK: ::std finds the namespace std
}

For an unqualified name, that is a name that does not appear to the right of a scope resolution operator ::, name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.

ADL(Argument-dependent lookup)

用于查找函数名

namespace A {
struct X;
struct Y;
void f(int);
void g(X);
}
namespace B {
void f(int i) {
f(i); // Calls B::f (endless recursion)
}
void g(A::X x) {
g(x); // Error: ambiguous between B::g (ordinary lookup)
// and A::g (argument-dependent lookup)
}
void h(A::Y y) {
h(y); // Calls B::h (endless recursion): ADL examines the A namespace
// but finds no A::h, so only B::h from ordinary lookup is used
}
}

Phases of translation

  1. 字符转换
  2. 删去换行符
  3. 分解为 注释, 空白字符, 预处理符号
  4. 预处理, include 的文件递归步骤 1-4
  5. 所有字符串文字量转换编码
  6. 连接相邻字符串
  7. token 在句法和语义上被分析并翻译为翻译单元。
  8. 处理模版?得到instantiation units
  9. Translation units, instantiation units, and library components needed to satisfy external references are collected into a program image which contains information needed for execution in its execution environment.

main 函数

  • It cannot be used anywhere in the program

  • The body of the main function does not need to contain the return statement: if control reaches the end of main without encountering a return statement, the effect is that of executing return 0;.

  • Execution of the return (or the implicit return upon reaching the end of main) is equivalent to first leaving the function normally (which destroys the objects with automatic storage duration) and then calling std::exit with the same argument as the argument of the return (std::exit then destroys static objects and terminates the program).

类型

cpp types.svg

Signedness: signed — target type will have signed representation (this is the default if omitted)(char 除外, char 是否带符号因编译器而异) unsigned — target type will have unsigned representation Size: short — target type will be optimized for space and will have width of at least 16 bits. long — target type will have width of at least 32 bits. long long — target type will have width of at least 64 bits.

type 类型

  • The value of sizeof(bool) is implementation defined and might differ from 1.

  • char 是否带符号因编译器而异

  • wchar_t — type for wide character representation (see wide strings).it is 32 bits and holds UTF-32 on Linux and many other non-Windows systems, but 16 bits and holds UTF-16 code units on Windows.

关键字

auto

使用 Template argument deduction 方法检测类型 The placeholder auto may be accompanied by modifiers, such as const or &, which will participate in the type deduction. 如果初始化表达式是引用,则去除引用语义 如果初始化表达式为const或volatile(或者两者兼有),则除去const/volatile语义。 如果auto关键字带上&号,则不去除const语义。 初始化表达式为数组时,auto关键字推导类型为指针。 如果表达式为数组且auto带上&,则推导类型为数组类型。

auto 的自动类型推断发生在编译期

const volatile

Any (possibly incomplete) type other than function type or reference type is a type in a group of the following four distinct but related types:

  1. A cv-unqualified version.
  2. A const-qualified version.
  3. A volatile-qualified version.
  4. A const-volatile-qualified version.

These four types in the same group have the same representation and alignment requirements. Array types are considered to have the same cv-qualification as their element types.

When an object is first created, the cv-qualifiers used (which could be part of decl-specifier-seq or part of a declarator in a declaration, or part of type-id in a new-expression) determine the constness or volatility of the object, as follows:

A const object is

  1. an object whose type is const-qualified, or
  2. a non-mutable subobject of a const object.

Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.

A volatile object is

  1. an object whose type is volatile-qualified,
  2. a subobject of a volatile object, or
  3. a mutable subobject of a const-volatile object.

volatile的主要作用是告知编译器变量可能会被无法预测的外部因素修改。例如,如果一个变量被内存映射到一个可以异步修改的硬件寄存器(比如在嵌入式系统中),使用volatile可以确保编译器始终从内存中读取和写入该变量,而不是将其值优化并缓存在寄存器中或执行其他优化。

A const volatile object is

  1. an object whose type is const-volatile-qualified,
  2. a non-mutable subobject of a const volatile object,
  3. a const subobject of a volatile object, or
  4. a non-mutable volatile subobject of a const object.

Behaves as both a const object and as a volatile object.

constexpr

specifies that the value of a variable or function can appear in constant expressions The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.

A constexpr specifier used in an object declaration or non-static member function implies const. A constexpr specifier used in a function declaration implies inline. If any declaration of a function or function template has a constexpr specifier, then every declaration must contain that specifier.

A constexpr variable must satisfy the following requirements:

  • its type must be a LiteralType
  • it must be immediately initialized
  • the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression

A constexpr function must satisfy the following requirements:

  • it must not be virtual
  • it must not be a function-try-block
  • for constructor, the class must have no virtual base classes
  • its return value (if any) and each of its parameters must be of a LiteralType
  • there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression (for constructors, use in a constant initializer is sufficient). No diagnostic is required for a violation of this bullet.
  • the function body must be either deleted or defaulted or contain only the following:
    • null statements (plain semicolons)
    • static_assert declarations
    • typedef declarations and alias declarations that do not define classes or enumerations
    • using declarations
    • using directives
    • if the function is not a constructor, exactly one return statement

const vs. constexpr

const 保证初始化后对象的值不变, 编译器可以利用这一点, 同时预防程序员修改 const 修饰 non-static成员函数(对函数也只能修饰non-static成员函数): 保证不修改 non-static 成员

constexpr declares an object as fit for use in what the Standard calls constant expressions. constexpr 修饰函数(普通函数, 成员函数, 构造函数等): 效果是符合 constant expressions 标准

Declaring something as constexpr does not necessarily guarantee that it will be evaluated at compile time. It can be used for such, but it can be used in other places that are evaluated at run-time, as well.

decltype

struct A { double x; };
const A* a;
decltype(a->x) y; // type of y is double (declared type)
decltype((a->x)) z = y; // type of z is const double& (lvalue expression)

new

The new expression attempts to allocate storage and then attempts to construct and initialize either a single unnamed object, or an unnamed array of objects in the allocated storage. The new-expression returns a prvalue pointer to the constructed object or, if an array of objects was constructed, a pointer to the initial element of the array.

If initialization terminates by throwing an exception (e.g. from the constructor), the program looks up a matching deallocation function, then:

  • If a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed. After that, the exception continues to propagate in the context of the new-expression.
  • If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object’s memory to be freed. It is only appropriate if the called allocation function does not allocate memory, otherwise it is likely to result in a memory leak.

new 返回 数据类型指针, malloc 返回 void* new 失败抛出bad_alloc异常, malloc 返回 null new 调用构造函数, malloc 不调用构造函数

delete

只可以删除以下指针

  1. ptr must be one of

    • a null pointer,

    • a pointer to a non-array object created by a new-expression, or

    • a pointer to a base subobject of a non-array object created by a new-expression.

    The pointed-to type of ptr must be similar to the type of the object (or of a base subobject). If ptr is anything else, including if it is a pointer obtained by the array form of new-expression, the behavior is undefined.

  2. ptr must be a null pointer or a pointer whose value is previously obtained by an array form of new-expression whose allocation function was not a non-allocating form (i.e. overload (10)). The pointed-to type of ptr must be similar to the element type of the array object. If ptr is anything else, including if it is a pointer obtained by the non-array form of new-expression, the behavior is undefined.

The result of the delete-expression always has type void.

If ptr is not a null pointer, the delete-expression invokes the destructor (if any) for the object that is being destroyed, or for every element of the array being destroyed (proceeding from the last element to the first element of the array).

对于将函数定义为 delete, 任何调用都是不允许的

struct sometype
{
void* operator new(std::size_t) = delete;
void* operator new[](std::size_t) = delete;
};
sometype* p = new sometype; // error: attempts to call deleted sometype::operator new

explicit

Specifies that a constructor or conversion function is explicit, that is, it cannot be used for implicit conversions and copy-initialization.

A constructor that is declared without the function specifier explicit is called a converting constructor.

struct A {
A(int) { } // converting constructor
A(int, int) { } // converting constructor (C++11)
operator bool() const { return true; }
};
struct B {
explicit B(int) { }
explicit B(int, int) { }
explicit operator bool() const { return true; }
};

int main() {
A a1 = 1; // OK: copy-initialization selects A::A(int)
A a2(2); // OK: direct-initialization selects A::A(int)
A a3 {4, 5}; // OK: direct-list-initialization selects A::A(int, int)
A a4 = {4, 5}; // OK: copy-list-initialization selects A::A(int, int)
A a5 = (A)1; // OK: explicit cast performs static_cast
if (a1) { } // OK: A::operator bool()
bool na1 = a1; // OK: copy-initialization selects A::operator bool()
bool na2 = static_cast<bool>(a1); // OK: static_cast performs direct-initialization

// B b1 = 1; // error: copy-initialization does not consider B::B(int)
B b2(2); // OK: direct-initialization selects B::B(int)
B b3 {4, 5}; // OK: direct-list-initialization selects B::B(int, int)
// B b4 = {4, 5}; // error: copy-list-initialization does not consider B::B(int, int)
B b5 = (B)1; // OK: explicit cast performs static_cast
if (b2) { } // OK: B::operator bool()
// bool nb1 = b2; // error: copy-initialization does not consider B::operator bool()
bool nb2 = static_cast<bool>(b2); // OK: static_cast performs direct-initialization

[](...){}(a4, a5, na1, na2, b5, nb2); // may suppress "unused variable" warnings
}

friend?

The friend declaration appears in a class body and grants a function or another class access to private and protected members of the class where the friend declaration appears.

class MyClass
{
int i; // friends have access to non-public, non-static
static inline int id{6}; // and static (possibly inline) members

friend std::ostream& operator<<(std::ostream& out, const MyClass&);
friend std::istream& operator>>(std::istream& in, MyClass&);
friend void change_id(int);
public:
MyClass(int i = 0) : i(i) {}
};

std::ostream& operator<<(std::ostream& out, const MyClass& mc)
{
return out << "MyClass::id = " << MyClass::id << "; i = " << mc.i;
}

std::istream& operator>>(std::istream& in, MyClass& mc)
{
return in >> mc.i;
}

void change_id(int id) { MyClass::id = id; }

int main()
{
MyClass mc(7);
std::cout << mc << '\n';
// mc.i = 333*2; // error: i is a private member
std::istringstream("100") >> mc;
std::cout << mc << '\n';
// MyClass::id = 222*3; // error: id is a private member
change_id(9);
std::cout << mc << '\n';
}

inline

A function defined entirely inside a class/struct/union definition, is implicitly an inline function.

A function declared constexpr on its first declaration is implicitly an inline function.

Instead of executing the function call CPU instruction to transfer control to the function body, a copy of the function body is executed without generating the call. This avoids overhead created by the function call (passing the arguments and retrieving the result) but it may result in a larger executable as the code for the function has to be repeated multiple times.

Since this meaning of the keyword inline is non-binding, compilers are free to use inline substitution for any function that's not marked inline, and are free to generate function calls to any function marked inline. Those optimization choices do not change the rules regarding multiple definitions and shared statics listed above.

类关键字

默认 private 继承, private 成员

关键字 成员
public 基类的 public protected 成员保留到子类 任何地方都可以访问
private 基类的 public protected 成员保留为 private 到子类 只能被成员访问
protected 基类的 public protected 成员保留为 protected 到子类 只能被成员或者 friend 访问; 或一级子类(不论如何继承)
多级子类需要看如何继承(继承后是否为 private)

sizeof

Queries size of the object or type. return std::size_t

The following sizeof expressions always evaluate to 1:

  • sizeof(char)
  • sizeof(signed char)
  • sizeof(unsigned char)

sizeof cannot be used with function types, incomplete types, or bit-field glvalues.

The result of sizeof is always nonzero, even if applied to an empty class type(sizeof(empty class) == 1).

When applied to an expression, sizeof does not evaluate the expression

int func() {
cout<<"!";
return 1;
}
int main() {
cout<<sizeof func();
cout<<sizeof (func());
}
// 4
// 4

override

Specifies that a virtual function overrides another virtual function.

virtual

virtual function

修饰 non-static 成员函数

使用 qualified name lookup (that is, if the function's name appears to the right of the scope resolution operator ::). virtual 会被抑制

虚函数继承: 如果Base 中有虚函数, 则 Derived 中的: 函数名, 参数列表(不包括返回值), cv 限定, ref 限定 都相同的函数也是虚函数(即使该函数式 private, 或继承方式是 private 也会虚拟并重载) If the function Derived::f overrides a function Base::f, their return types must either be the same or be covariant. Two types are covariant if they satisfy all of the following requirements:

  • both types are pointers or references (lvalue or rvalue) to classes. Multi-level pointers or references are not allowed.
  • the referenced/pointed-to class in the return type of Base::f() must be an unambiguous and accessible direct or indirect base class of the referenced/pointed-to class of the return type of Derived::f().
  • the return type of Derived::f() must be equally or less cv-qualified than the return type of Base::f().

When a virtual function call is made, the type returned by the final overrider is implicitly converted to the return type of the overridden function that was called

一个虚函数只能有一个最终形态

// 覆盖问题
struct B {
virtual void f();
};
struct D : B {
void f(int); // D::f hides B::f (wrong parameter list)
};
struct D2 : D {
void f(); // D2::f overrides B::f (doesn't matter that it's not visible)
};

int main() {
B b;
B& b_as_b = b;

D d;
B& d_as_b = d;
D& d_as_d = d;

D2 d2;
B& d2_as_b = d2;
D& d2_as_d = d2;

b_as_b.f(); // calls B::f()
d_as_b.f(); // calls B::f()
d2_as_b.f(); // calls D2::f()

d_as_d.f(); // Error: lookup in D finds only f(int)
d2_as_d.f(); // Error: lookup in D finds only f(int)
}

Default arguments for virtual functions are substituted at the compile time.

virtual 虚构函数: 先调用 derived 析构再调用 base 析构 A useful guideline is that the destructor of any base class must be public and virtual or protected and non-virtual, whenever delete expressions are involved.

构造函数或析构函数中调用 virtual function When a virtual function is called directly or indirectly from a constructor or from a destructor (including during the construction or destruction of the class’s non-static data members, e.g. in a member initializer list), and the object to which the call applies is the object under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. In other words, during construction or destruction, the more-derived classes do not exist.

struct V {
virtual void f();
virtual void g();
};
struct A : virtual V {
virtual void f(); // A::f is the final overrider of V::f in A
};
struct B : virtual V {
virtual void g(); // B::g is the final overrider of V::g in B
B(V*, A*);
};
struct D : A, B {
virtual void f(); // D::f is the final overrider of V::f in D
virtual void g(); // D::g is the final overrider of V::g in D
// note: A is initialized before B
D() : B((A*) this, this) {}
};

// the constructor of B, called from the constructor of D
B::B(V* v, A* a) {
f(); // virtual call to V::f (although D has the final overrider, D doesn't exist)
g(); // virtual call to B::g, which is the final overrider in B
v->g(); // v's type V is base of B, virtual call calls B::g as before
a->f(); // a’s type A is not a base of B. it belongs to a different branch of the
// hierarchy. Attempting a virtual call through that branch causes
// undefined behavior even though A was already fully constructed in this
// case (it was constructed before B since it appears before B in the list
// of the bases of D).

// In practice, the virtual call to A::f will be
// attempted using B's virtual member function table, since that's what
// is active during B's construction)
}

virtual inheritance

For each distinct base class that is specified virtual, the most derived object contains only one base class subobject of that type, even if the class appears many times in the inheritance hierarchy (as long as it is inherited virtual every time).

All virtual base subobjects are initialized before any non-virtual base subobject, so only the most derived class calls the constructors of the virtual bases in its member initializer list.

struct B { int n; };
class X : public virtual B {};
class Y : virtual public B {};
class Z : public B {};
// every object of type AA has one X, one Y, one Z, and two B's:
// one that is the base of Z and one that is shared by X and Y
struct AA : X, Y, Z {
AA() {
X::n = 1; // modifies the virtual B subobject's member
Y::n = 2; // modifies the same virtual B subobject's member
Z::n = 3; // modifies the non-virtual B subobject's member
std::cout << X::n << Y::n << Z::n << '\n'; // prints 223
}
};

存储关键字

默认情况下是automatic storage duration.

storage duration

  • automatic storage duration. The storage for the object is allocated at the beginning of the enclosing code block and deallocated at the end. 生存在代码块范围内
  • static storage duration. The storage for the object is allocated when the program begins and deallocated when the program ends. 生存在程序开始和程序结束之间. Only one instance of the object exists. All objects declared at namespace scope (including global namespace) have this storage duration, plus those declared with static or extern.
  • thread storage duration. The storage for the object is allocated when the thread begins and deallocated when the thread ends. 生存在线程开始和线程结束之间. Each thread has its own instance of the object.
  • dynamic storage duration. The storage for the object is allocated and deallocated upon request by using dynamic memory allocation functions. 生存范围手动决定 new delete

linkage

  • No linkage The name can be referred to only from the scope it is in. 一般在代码块内的无static extern 的都是 no linkage

  • Internal linkage The name can be referred to from all scopes in the current translation unit.

    在命名空间内 variables of non-volatile const-qualified type, unless

    • they are explicitly declared extern, or
    • they were previously declared and the prior declaration did not have internal linkage;
  • External linkage The name can be referred to from the scopes in the other translation units. Variables and functions with external linkage also have language linkage, which makes it possible to link translation units written in different programming languages.

    Any of the following names declared at namespace scope have external linkage, unless they are declared in an unnamed namespace:

    • variables and functions not listed above (that is, functions not declared static, non-const variables not declared static, and any variables declared extern);
    • enumerations;
    • names of classes, their member functions, static data members (const or not), nested classes and enumerations, and functions first introduced with
    • friend declarations inside class bodies;
    • names of all templates not listed above (that is, not function templates declared static).
    • Any of the following names first declared at block scope have external linkage:
      • names of variables declared extern;
      • names of functions.

register

automatic storage duration. Also hints to the compiler to place the object in the processor's register. (已被遗弃)

static

static or thread storage duration and internal linkage

When used in a declaration of a class member, it declares a static member. When used in a declaration of an object, it specifies static storage duration (except if accompanied by thread_local). When used in a declaration at namespace scope, it specifies internal linkage.

extern

static or thread storage duration and external linkage.

It specifies external linkage it cannot be used in a definition of an automatic storage duration object, so all extern objects have static or thread durations.

thread_local

thread storage duration.

It indicates that the object has thread storage duration. If thread_local is the only storage class specifier applied to a block scope variable, static is also implied. It can be combined with static or extern to specify internal or external linkage (except for static data members which always have external linkage) respectively.

mutable

影响 const 和 volatile

  • mutable - permits modification of the class member declared mutable even if the containing object is declared const (i.e., the class member is mutable).

类型转换

const_cast

dynamic_cast

Safely converts pointers and references to classes up, down, and sideways along the inheritance hierarchy.

如果成功, 返回对应类型的 value 如果失败

  • 如果是指针, 返回 null
  • 如果是引用, throw std::bad_cast

表达式

Constant expressions

定义编译时可以取得的值

可以用于: 模版参数, 数组长度等

不包括以下所有计算的expression 是 core constant expression

  1. this 指针(除了?)
  2. static or thread-local storage duration?
  3. 不是 constexpr 的函数调用
  4. 左右值转换?
  5. new delete
  6. throw

A constant expression is either

  • an lvalue core constant expression that refers to
    • an object with static storage duration that is not a temporary, or
    • a function
  • a prvalue core constant expression whose value satisfies the following constraints:
    • if the value is an object of class type, each non-static data member of reference type refers to an entity that satisfies the constraints for lvalues above
    • if the value is of pointer type, it holds
      • address of an object with static storage duration
      • address past the end of an object with static storage duration
      • address of a function
      • a null pointer value
    • if the value is an object of class or array type, each subobject satisfies these constraints for values

值类型

操作符

alignof

If the type is reference type, the operator returns the alignment of referenced type; if the type is array type, alignment requirement of the element type is returned.

struct Foo {
int i;
float f;
char c;
};
struct alignas(alignof(long double)) Foo2 {};
struct Empty {};
int main()
{
std::cout << "Alignment of" "\n"
"- char : " << alignof(char) << "\n"
"- pointer : " << alignof(int*) << "\n"
"- class Foo : " << alignof(Foo) << "\n"
"- class Foo2 : " << alignof(Foo2) << "\n"
"- empty class : " << alignof(Empty) << "\n"
}
/*
Alignment of
- char : 1
- pointer : 8
- class Foo : 4
- class Foo2 : 16
- empty class : 1
*/

std

vector

  • 构造函数

    int main()
    {
    // C++11 initializer list syntax:
    std::vector<std::string> words1{"the", "frogurt", "is", "also", "cursed"};
    std::cout << "1: " << words1;

    // words2 == words1
    std::vector<std::string> words2(words1.begin(), words1.end());
    std::cout << "2: " << words2;

    // words3 == words1
    std::vector<std::string> words3(words1);
    std::cout << "3: " << words3;

    // words4 is {"Mo", "Mo", "Mo", "Mo", "Mo"}
    std::vector<std::string> words4(5, "Mo");
    std::cout << "4: " << words4;
    }

  • 倒数第二个元素

    int mySize = vec.size();

    vec.at(mySize -2);比*(vec.end() - 2)

  • v.empty()

  • v.size() 元素数量

  • v.clear()

  • v.insert()都是在 pos 之前插入(如果要插到尾部用 pos=end())

    1. iterator insert( const_iterator pos, const T& value );
    2. iterator insert( const_iterator pos, T&& value );
    3. iterator insert( const_iterator pos, size_type count, const T& value );
    4. template< class InputIt >
    5. iterator insert( const_iterator pos, InputIt first, InputIt last );
    6. iterator insert( const_iterator pos, std::initializer_list ilist );
  • v.erase()

    1. iterator erase( const_iterator pos );删除 pos 位置的元素
    2. iterator erase( const_iterator first, const_iterator last );删除 [first, last) 位置的元素
  • v.swap(vector& other) Exchanges the contents and capacity of the container with those of other. Does not invoke any move, copy, or swap operations on individual elements.

  • v.resize()

    void resize( size_type count ); void resize( size_type count, const value_type& value ); Resizes the container to contain count elements, does nothing if count == size().

    If the current size is greater than count, the container is reduced to its first count elements.

    If the current size is less than count,

    1. additional default-inserted elements are appended.
    2. additional copies of value are appended.
  • void swap( std::vector<T, Alloc>& lhs, std::vector<T, Alloc>& rhs );

其他

编译时 运行时

Compile-time constants Run-time constants
1. A compile-time constant is a value that is computed at the compilation-time. Whereas, A runtime constant is a value that is computed only at the time when the program is running.
2. A compile-time constant will have the same value each time when the source code is run. A runtime constant can have a different value each time the source code is run.
3 It is generally used while declaring an array size. It is not preferred for declaring an array size.
4 If you use const int size = 5 for defining a case expression it would run smoothly and won’t produce any compile-time error. Here, if you use run-time constant in your source code for defining case expression then it will yield a compile-time error.
5 It does not produces any compile time error when used for initializing an enumerator. Same compilation error, if runtime constant is used for initializing an enumerator.

null nullptr

nullptr has type std::nullptr_t. It's implicitly convertible to any pointer type. Thus, it'll match std::nullptr_t or pointer types in overload resolution, but not other types such as int.

0 (aka. C's NULL bridged over into C++) could cause ambiguity in overloaded function resolution

named requirements

LiteralType

A literal type is any of the following:

  • scalar type;
  • reference type;
  • an array of literal type;
  • possibly cv-qualified class type that has all of the following properties:
    • has a trivial destructor,
      • is one of
        • an aggregate union type that
          • has no variant members, or
          • has at least one variant member of non-volatile literal type,
        • a non-union aggregate type, and each of its anonymous union members
          • has no variant members, or
          • has at least one variant member of non-volatile literal type,
        • a type with at least one constexpr (possibly template) constructor that is not a copy or move constructor,

cpp memory layout

整体分区

  1. text segment Also, know as Code segment, Contains executable instructions. Usually, Text segment is sharable and hence only a single copy exists as well as its read-only.

  2. data segment 分为两部分

    1. 初始化数据区

      包括初始化了的 global 和 static 变量

    2. 未初始化数据区(BSS segment)

      在程序执行前由 kernal 初始化为 0

  3. stack 存放临时变量和虚指针? stack frame: 一次函数调用 push 进 stack 的一组值

  4. heap 动态分配

对象内存布局

简单对象

  1. stack
    1. 成员变量
  2. text segment
    1. 成员函数

有 virtual 和 static 的对象

  1. stack
    1. 成员变量
    2. _vptr
  2. text segment
    1. 成员函数
    2. static 成员函数
  3. data segment
    1. 静态成员变量

有继承的对象

  1. stack
    1. 派生类和父类成员变量
    2. _vptr
  2. text segment
    1. 派生类父类成员函数

多继承和虚函数的对象

  1. stack
    1. 成员变量
    2. 每个父类对应一个 _vptr
  2. text segment
    1. 成员函数

表?

类型 生存周期 linkage 其他 ?
local variable automatic storage duration No linkage
global variable
function External linkage
member variable
member function External linkage
class? External linkage
static variable static storage duration Internal linkage Only one instance of the object exists
static function Internal linkage
static member variable External linkage
static member function
extern variable static storage duration External linkage
extern function
extern member variable
extern member function

tips