c++速成

C++ 的关键字:

  1. alignas
  2. alignof
  3. and
  4. and_eq
  5. asm
  6. atomic_cancel
  7. atomic_commit
  8. atomic_noexcept
  9. auto
  10. bitand
  11. bitor
  12. bool
  13. break
  14. case
  15. catch
  16. char
  17. char8_t
  18. char16_t
  19. char32_t
  20. class
  21. co_await
  22. co_return
  23. co_yield
  24. compl
  25. concept
  26. const
  27. consteval
  28. constexpr
  29. constinit
  30. const_cast
  31. continue
  32. decltype
  33. default
  34. delete
  35. do
  36. double
  37. dynamic_cast
  38. else
  39. enum
  40. explicit
  41. export
  42. extern
  43. false
  44. float
  45. for
  46. friend
  47. goto
  48. if
  49. inline
  50. int
  51. long
  52. mutable
  53. namespace
  54. new
  55. noexcept
  56. not
  57. not_eq
  58. nullptr
  59. operator
  60. or
  61. or_eq
  62. private
  63. protected
  64. public
  65. register
  66. reinterpret_cast
  67. requires
  68. return
  69. short
  70. signed
  71. sizeof
  72. static
  73. static_assert
  74. static_cast
  75. struct
  76. switch
  77. synchronized
  78. template
  79. this
  80. thread_local
  81. throw
  82. true
  83. try
  84. typedef
  85. typeid
  86. typename
  87. union
  88. unsigned
  89. using
  90. virtual
  91. void
  92. volatile
  93. wchar_t
  94. while
  95. xor
  96. xor_eq

C++14 关键字使用演示

  1. auto (类型推导)

    #include
    #include

    int main() {
    // 自动推导出 i 的类型为 int
    auto i = 10;

    // 自动推导出 v 的类型为 std::vector
    auto v = std::vector{1, 2, 3};

    // 使用 auto 简化迭代器类型
    for (auto it = v.begin(); it != v.end(); ++it) {
    std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
    }

  2. decltype (类型获取)

    #include

    int main() {
    int a = 10;
    // 获取 a 的类型并定义相同类型的变量 b
    decltype(a) b = 20;

    // 使用 decltype 推导出函数返回值类型
    auto sum = [](int x, int y) -> decltype(x + y) { return x + y; };

    std::cout << "a + b = " << sum(a, b) << std::endl;

    return 0;
    }

  3. constexpr (常量表达式)

    #include

    constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
    }

    int main() {
    // 在编译期计算阶乘
    constexpr int result = factorial(5);

    // 使用常量表达式初始化数组大小
    int arr[result] = {};

    std::cout << "5! = " << result << std::endl;

    return 0;
    }

  4. lambda 表达式 (匿名函数)

    #include
    #include
    #include

    int main() {
    std::vector v = {1, 5, 3, 2, 4};

    // 使用 lambda 表达式排序
    std::sort(v.begin(), v.end(), [](int a, int b) { return a < b; });

    // 使用 lambda 表达式输出
    std::for_each(v.begin(), v.end(), [](int x) { std::cout << x << " "; });
    std::cout << std::endl;

    return 0;
    }

其他重要关键字:

  • default/delete (控制默认函数生成): 控制编译器是否生成默认构造函数、拷贝构造函数、赋值运算符等。

  • nullptr (空指针): 更安全的空指针表示,避免与整型 0 混淆。

  • [[deprecated]] (标记废弃): 标记废弃的函数、类或变量,编译器会给出警告。

  • 数字分隔符 (提高可读性): 使用单引号分隔数字,例如 1’000’000。

    #include // 使用#include指令包含输入输出流库

    // 定义一个宏,用于输出调试信息
    #define DEBUG(x) std::cout << x << std::endl

    // 声明一个命名空间
    namespace MyNamespace {
    // 定义一个类
    class MyClass {
    public:
    // 构造函数
    MyClass(int a) : value(a) {}

          // 声明一个静态成员函数
          static void staticFunction() {
              DEBUG("Static function called");
          }
    
          // 声明一个常成员函数
          void constFunction() const {
              DEBUG("Const function called with value: " << value);
          }
    
          // 重载运算符
          MyClass operator+(const MyClass& other) const {
              return MyClass(value + other.value);
          }
    
      private:
          // 声明一个成员变量
          int value;
      };
    

    }

    // 主函数
    int main() {
    // 声明变量
    int x = 10;
    int y = 20;

      // 使用if语句
      if (x < y) {
          DEBUG("x is less than y");
      } else {
          DEBUG("x is not less than y");
      }
    
      // 使用循环
      for (int i = 0; i < 5; ++i) {
          DEBUG("i: " << i);
      }
    
      // 使用指针和动态分配
      int* ptr = new int(30);
      DEBUG("Pointer value: " << *ptr);
      delete ptr;  // 释放动态分配的内存
    
      // 使用命名空间中的类
      MyNamespace::MyClass obj1(100);
      MyNamespace::MyClass obj2(200);
    
      // 调用类的静态函数
      MyNamespace::MyClass::staticFunction();
    
      // 调用类的常成员函数
      obj1.constFunction();
    
      // 使用运算符重载
      MyNamespace::MyClass obj3 = obj1 + obj2;
      obj3.constFunction();
    
      // 使用switch语句
      switch (x) {
          case 10:
              DEBUG("x is 10");
              break;
          default:
              DEBUG("x is not 10");
              break;
      }
    
      // 返回值
      return 0;
    

    }

  1. const 关键字:

    #include

    int main() {
    // 定义一个常量
    const int MAX_VALUE = 100;

    // 尝试修改常量,会报错
    // MAX_VALUE = 200;

    std::cout << "MAX_VALUE: " << MAX_VALUE << std::endl;

    return 0;
    }

  2. enum 关键字:

    #include

    enum Color { RED, GREEN, BLUE };

    int main() {
    Color myColor = GREEN;

    if (myColor == GREEN) {
    std::cout << “Color is GREEN” << std::endl;
    }

    return 0;
    }

  3. struct 关键字:

    #include

    struct Point {
    int x;
    int y;
    };

    int main() {
    Point p1 = {10, 20};

    std::cout << “Point: (” << p1.x << ", " << p1.y << “)” << std::endl;

    return 0;
    }

  4. union 关键字:

    #include

    union Data {
    int i;
    float f;
    };

    int main() {
    Data data;
    data.i = 10;

    std::cout << "Integer value: " << data.i << std::endl;

    data.f = 3.14f;

    std::cout << "Float value: " << data.f << std::endl;

    return 0;
    }

  5. typedef 关键字:

    #include

    typedef int Integer;

    int main() {
    Integer num = 10;

    std::cout << "Integer value: " << num << std::endl;

    return 0;
    }

  6. volatile 关键字:

    #include

    volatile int counter = 0;

    int main() {
    // 在多线程环境中,counter 的值可能会被其他线程修改
    // 使用 volatile 关键字,确保每次访问 counter 都从内存中读取
    for (int i = 0; i < 10; ++i) {
    counter++;
    std::cout << "Counter: " << counter << std::endl;
    }

    return 0;
    }

  7. extern 关键字:

    // file1.cpp
    int global_var = 10;

    // file2.cpp
    #include
    extern int global_var;

    int main() {
    std::cout << "Global variable: " << global_var << std::endl;

    return 0;
    }

  8. explicit 关键字:

    #include

    class MyClass {
    public:
    explicit MyClass(int value) : value(value) {}//显式

    int getValue() const {
    return value;
    }

    private:
    int value;
    };

    int main() {
    // 由于构造函数是 explicit 的,无法隐式转换
    // MyClass obj = 10; // 错误

    // 需要显式调用构造函数
    MyClass obj(10);

    std::cout << "Value: " << obj.getValue() << std::endl;

    return 0;
    }

  9. friend 关键字:

    #include

    class MyClass {
    public:
    friend void printValue(MyClass obj);

    MyClass(int value) : value(value) {}

    private:
    int value;
    };

    void printValue(MyClass obj) {
    std::cout << "Value: " << obj.value << std::endl;
    }

    int main() {
    MyClass obj(10);
    printValue(obj);

    return 0;
    }

  10. sizeof 关键字:

    #include

    int main() {
    int num = 10;
    std::cout << "Size of int: " << sizeof(num) << std::endl;

    return 0;
    }

  11. nullptr 关键字:

    #include

    int main() {
    int* ptr = nullptr;

    if (ptr == nullptr) {
    std::cout << “Pointer is null” << std::endl;
    }

    return 0;
    }

  12. alignof 关键字:

    #include

    int main() {
    int num = 10;
    std::cout << "Alignment of int: " << alignof(num) << std::endl;

    return 0;
    }

  13. decltype 关键字:

    #include

    int main() {
    int num = 10;
    decltype(num) anotherNum = 20;

    std::cout << "Another number: " << anotherNum << std::endl;

    return 0;
    }

  14. noexcept 关键字:

    #include

    int add(int a, int b) noexcept {
    return a + b;
    }

    int main() {
    int result = add(10, 20);

    std::cout << "Result: " << result << std::endl;

    return 0;
    }

  15. constexpr 关键字:

    #include

    constexpr int square(int x) {
    return x * x;
    }

    int main() {
    constexpr int result = square(5);

    std::cout << "Result: " << result << std::endl;

    return 0;
    }

  16. auto 关键字:

    #include

    int main() {
    auto num = 10; // 自动推断类型为 int
    auto str = “Hello”; // 自动推断类型为 const char*

    std::cout << "Number: " << num << std::endl;
    std::cout << "String: " << str << std::endl;

    return 0;
    }

  17. override 关键字:

    #include

    class Base {
    public:
    virtual void print() {
    std::cout << “Base class” << std::endl;
    }
    };

    class Derived : public Base {
    public:
    void print() override {
    std::cout << “Derived class” << std::endl;
    }
    };

    int main() {
    Derived derived;
    derived.print();

    return 0;
    }

  18. final 关键字:

    #include

    class Base {
    public:
    virtual void print() final {
    std::cout << “Base class” << std::endl;
    }
    };

    // 无法继承 Base 类并重写 print() 方法
    // class Derived : public Base {
    // void print() override; // 错误
    // };

    int main() {
    Base base;
    base.print();

    return 0;
    }

  19. using 关键字:

    #include

    namespace MyNamespace {
    int value = 10;
    }

    int main() {
    using namespace MyNamespace;

    std::cout << "Value: " << value << std::endl;

    return 0;
    }

  20. delete 关键字:

    #include

    class MyClass {
    public:
    MyClass() {
    std::cout << “Constructor called” << std::endl;
    }

    ~MyClass() {
    std::cout << “Destructor called” << std::endl;
    }
    };

    int main() {
    MyClass* obj = new MyClass();

    delete obj; // 调用析构函数

    return 0;
    }

  21. dynamic_cast 关键字:

    #include

    class Base {
    public:
    virtual void print() {
    std::cout << “Base class” << std::endl;
    }
    };

    class Derived : public Base {
    public:
    void print() override {
    std::cout << “Derived class” << std::endl;
    }
    };

    int main() {
    Base* basePtr = new Derived();

    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);

    if (derivedPtr != nullptr) {
    derivedPtr->print();
    } else {
    std::cout << “Conversion failed” << std::endl;
    }

    return 0;
    }

  22. reinterpret_cast 关键字:

    #include

    int main() {
    int num = 10;
    char* charPtr = reinterpret_cast<char*>(&num);

    std::cout << "Character value: " << *charPtr << std::endl;

    return 0;
    }

  23. static_cast 关键字:

    #include

    int main() {
    double d = 3.14;
    int i = static_cast(d);

    std::cout << "Integer value: " << i << std::endl;

    return 0;
    }

  24. const_cast 关键字:

    #include

    int main() {
    const int num = 10;

    int* ptr = const_cast<int*>(&num);

    *ptr = 20;

    std::cout << "Modified value: " << num << std::endl;

    return 0;
    }

  25. typeid 关键字:

    #include
    #include

    class MyClass {};

    int main() {
    MyClass obj;

    std::cout << "Type of object: " << typeid(obj).name() << std::endl;

    return 0;
    }

  26. throw 关键字:

    #include
    #include

    int divide(int a, int b) {
    if (b == 0) {
    throw std::runtime_error(“Division by zero”);
    }

    return a / b;
    }

    int main() {
    try {
    int result = divide(10, 0);
    std::cout << "Result: " << result << std::endl;
    } catch (const std::runtime_error& e) {
    std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
    }

  27. try 关键字:

    #include
    #include

    int main() {
    try {
    // 代码块,可能抛出异常
    throw std::runtime_error(“An error occurred”);
    } catch (const std::runtime_error& e) {
    std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
    }

  28. catch 关键字:

    #include
    #include

    int main() {
    try {
    // 代码块,可能抛出异常
    throw std::runtime_error(“An error occurred”);
    } catch (const std::runtime_error& e) {
    std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
    }

  29. template 关键字:

    #include

    template
    T sum(T a, T b) {
    return a + b;
    }

    int main() {
    int result1 = sum(10, 20);
    double result2 = sum(3.14, 2.71);

    std::cout << "Integer sum: " << result1 << std::endl;
    std::cout << "Double sum: " << result2 << std::endl;

    return 0;
    }

  30. typename 关键字:

    #include

    template
    class MyClass {
    public:
    typename T::type value;
    };

    int main() {
    MyClass<std::pair<int, double>> obj;

    obj.value.first = 10;
    obj.value.second = 3.14;

    std::cout << “Value: (” << obj.value.first << ", " << obj.value.second << “)” << std::endl;

    return 0;
    }

  31. operator 关键字:

    #include

    class MyClass {
    public:
    MyClass(int value) : value(value) {}

    MyClass operator+(const MyClass& other) const {
    return MyClass(value + other.value);
    }

    int getValue() const {
    return value;
    }

    private:
    int value;
    };

    int main() {
    MyClass obj1(10);
    MyClass obj2(20);

    MyClass obj3 = obj1 + obj2;

    std::cout << "Sum: " << obj3.getValue() << std::endl;

    return 0;
    }

  32. this 关键字:

    #include

    class MyClass {
    public:
    MyClass(int value) : value(value) {}

    void printValue() {
    std::cout << "Value: " << this->value << std::endl;
    }

    private:
    int value;
    };

    int main() {
    MyClass obj(10);
    obj.printValue();

    return 0;
    }

  33. new 关键字:

    #include

    class MyClass {
    public:
    MyClass() {
    std::cout << “Constructor called” << std::endl;
    }

    ~MyClass() {
    std::cout << “Destructor called” << std::endl;
    }
    };

    int main() {
    MyClass* obj = new MyClass();

    delete obj; // 释放内存

    return 0;
    }

  34. delete 关键字:

    #include

    class MyClass {
    public:
    MyClass() {
    std::cout << “Constructor called” << std::endl;
    }

    ~MyClass() {
    std::cout << “Destructor called” << std::endl;
    }
    };

    int main() {
    MyClass* obj = new MyClass();

    delete obj; // 调用析构函数

    return 0;
    }

  35. mutable 关键字:

    #include

    class MyClass {
    public:
    MyClass(int value) : value(value) {}

    void increment() const {
    mutable int counter = 0;
    counter++;
    std::cout << "Counter: " << counter << std::endl;
    }

    private:
    int value;
    };

    int main() {
    MyClass obj(10);
    obj.increment();

    return 0;
    }

  36. inline 关键字:

    #include

    inline int add(int a, int b) {
    return a + b;
    }

    int main() {
    int result = add(10, 20);

    std::cout << "Result: " << result << std::endl;

    return 0;
    }

  37. virtual 关键字:

    #include

    class Base {
    public:
    virtual void print() {
    std::cout << “Base class” << std::endl;
    }
    };

    class Derived : public Base {
    public:
    void print() override {
    std::cout << “Derived class” << std::endl;
    }
    };

    int main() {
    Base* basePtr = new Derived();

    basePtr->print(); // 调用 Derived 类的 print() 方法

    return 0;
    }

  38. explicit 关键字:

    #include

    class MyClass {
    public:
    explicit MyClass(int

#include
#include
#include
#include
#include
#include

// 1. auto 关键字:自动类型推断
void autoExample() {
auto num = 10; // 自动推断为 int
auto str = “Hello”; // 自动推断为 const char*
std::vector vec = {1, 2, 3};
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
}

// 2. decltype 关键字:获取表达式类型
void decltypeExample() {
int a = 10;
decltype(a) b = 20; // b 的类型为 int
auto sum = [](int x, int y) -> decltype(x + y) { return x + y; };
std::cout << "a + b = " << sum(a, b) << std::endl;
}

// 3. constexpr 关键字:常量表达式
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
void constexprExample() {
constexpr int result = factorial(5); // 在编译时计算
int arr[result] = {}; // 使用常量表达式初始化数组大小
std::cout << "5! = " << result << std::endl;
}

// 4. lambda 表达式:匿名函数
void lambdaExample() {
std::vector v = {1, 5, 3, 2, 4};
std::sort(v.begin(), v.end(), [](int a, int b) { return a < b; });
std::for_each(v.begin(), v.end(), [](int x) { std::cout << x << " "; });
std::cout << std::endl;
}

// 5. default/delete 关键字:控制默认函数生成
class MyClass {
public:
MyClass() = default; // 使用默认构造函数
MyClass(const MyClass&) = delete; // 禁止拷贝构造函数
MyClass& operator=(const MyClass&) = delete; // 禁止赋值运算符
};
void defaultDeleteExample() {
MyClass obj1;
// MyClass obj2 = obj1; // 错误:禁止拷贝构造
// obj1 = obj2; // 错误:禁止赋值运算符
}

// 6. nullptr 关键字:空指针
void nullptrExample() {
int* ptr = nullptr;
if (ptr == nullptr) {
std::cout << “Pointer is null” << std::endl;
}
}

// 7. [[deprecated]] 关键字:标记废弃
[[deprecated(“Use newFunction instead”)]]
void oldFunction() {
std::cout << “Old function called” << std::endl;
}
void newFunction() {
std::cout << “New function called” << std::endl;
}
void deprecatedExample() {
oldFunction(); // 编译器会给出警告
newFunction();
}

// 8. 数字分隔符:提高可读性
void numberSeparatorExample() {
long long bigNumber = 1’000’000’000;
std::cout << "Big number: " << bigNumber << std::endl;
}

// 9. override 关键字:重写虚函数
class Base {
public:
virtual void print() {
std::cout << “Base class” << std::endl;
}
};

class Derived : public Base {
public:
void print() override {
std::cout << “Derived class” << std::endl;
}
};
void overrideExample() {
Derived derived;
derived.print();
}
Public继承:

公开继承(public inheritance)意味着基类的公有成员在派生类中保持为公有成员,保护成员在派生类中保持为保护成员,私有成员在派生类中不可直接访问。
派生类的对象可以被视为基类的对象,可以通过指向派生类对象的基类指针或引用来访问基类的成员。
Private继承:

私有继承(private inheritance)意味着基类的公有和保护成员在派生类中变为私有成员,无法直接访问。
派生类对象不能被视为基类对象,只能通过派生类的成员函数来访问基类的成员。
Protected继承:

保护继承(protected inheritance)意味着基类的公有和保护成员在派生类中变为保护成员,只能在派生类内部或其派生类中访问。
派生类对象不能被视为基类对象,只能通过派生类的成员函数来访问基类的成员。

// 10. final 关键字:阻止继承或重写
class BaseFinal {
public:
virtual void print() final {
std::cout << “BaseFinal class” << std::endl;
}
};

// class DerivedFinal : public BaseFinal { // 错误:无法继承
// void print() override; // 错误:无法重写
// };
void finalExample() {
BaseFinal baseFinal;
baseFinal.print();
}

// 11. static_cast 关键字:显式类型转换
void staticCastExample() {
double d = 3.14;
int i = static_cast(d);
std::cout << "Integer value: " << i << std::endl;
}

// 12. reinterpret_cast 关键字:重新解释数据类型
void reinterpretCastExample() {
int num = 10;
char* charPtr = reinterpret_cast<char*>(&num);
std::cout << "Character value: " << *charPtr << std::endl;
}

// 13. const_cast 关键字:修改 const 限定符
void constCastExample() {
const int num = 10;
int* ptr = const_cast<int*>(&num);
*ptr = 20;
std::cout << "Modified value: " << num << std::endl;
}

// 14. dynamic_cast 关键字:动态类型转换
class Base {
public:
virtual void print() {
std::cout << “Base class” << std::endl;
}
};

class Derived : public Base {
public:
void print() override {
std::cout << “Derived class” << std::endl;
}
};
void dynamicCastExample() {
Base* basePtr = new Derived();
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr != nullptr) {
derivedPtr->print();
} else {
std::cout << “Conversion failed” << std::endl;
}
delete basePtr;
}

// 15. typeid 关键字:获取类型信息
void typeidExample() {
int num = 10;
std::cout << "Type of num: " << typeid(num).name() << std::endl;
std::string str = “Hello”;
std::cout << "Type of str: " << typeid(str).name() << std::endl;
}

// 16. throw 关键字:抛出异常
void throwExample() {
try {
throw std::runtime_error(“An error occurred”);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}

// 17. try 关键字:异常处理块
void tryExample() {
try {
// 可能抛出异常的代码
throw std::runtime_error(“An error occurred”);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}

// 18. catch 关键字:捕获异常
void catchExample() {
try {
// 可能抛出异常的代码
throw std::runtime_error(“An error occurred”);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}

// 19. template 关键字:模板
template
T sum(T a, T b) {
return a + b;
}
void templateExample() {
int result1 = sum(10, 20);
double result2 = sum(3.14, 2.71);
std::cout << "Integer sum: " << result1 << std::endl;
std::cout << "Double sum: " << result2 << std::endl;
}

// 20. typename 关键字:在模板中使用依赖类型
template
class MyClass {
public:
typename T::type value;
};
void typenameExample() {
MyClass<std::pair<int, double>> obj;
obj.value.first = 10;
obj.value.second = 3.14;
std::cout << “Value: (” << obj.value.first << ", " << obj.value.second << “)” << std::endl;
}

// 21. operator 关键字:运算符重载
class MyClass {
public:
MyClass(int value) : value(value) {}
MyClass operator+(const MyClass& other) const {
return MyClass(value + other.value);
}
int getValue() const {
return value;
}
private:
int value;
};
void operatorExample() {
MyClass obj1(10);
MyClass obj2(20);
MyClass obj3 = obj1 + obj2;
std::cout << "Sum: " << obj3.getValue() << std::endl;
}

// 22. this 关键字:指向当前对象的指针
class MyClass {
public:
MyClass(int value) : value(value) {}
void printValue() {
std::cout << "Value: " << this->value << std::endl;
}
private:
int value;
};
void thisExample() {
MyClass obj(10);
obj.printValue();
}

// 23. new 关键字:动态内存分配
void newExample() {
int* ptr = new int(10);
std::cout << "Value: " << *ptr << std::endl;
delete ptr;
}

// 24. delete 关键字:释放动态内存
void deleteExample() {
int* ptr = new int(10);
delete ptr;
}

// 25. mutable 关键字:允许在 const 成员函数中修改数据成员
class MyClass {
public:
MyClass(int value) : value(value) {}
void increment() const {
mutable int counter = 0;
counter++;
std::cout << "Counter: " << counter << std::endl;
}
private:
int value;
};
void mutableExample() {
MyClass obj(10);
obj.increment();
}

// 26. inline 关键字:建议编译器将函数内联
inline int add(int a, int b) {
return a + b;
}
void inlineExample() {
int result = add(10, 20);
std::cout << "Result: " << result << std::endl;
}

// 27. virtual 关键字:虚函数
class Base {
public:
virtual void print() {
std::cout << “Base class” << std::endl;
}
};

class Derived : public Base {
public:
void print() override {
std::cout << “Derived class” << std::endl;
}
};
void virtualExample() {
Base* basePtr = new Derived();
basePtr->print(); // 调用 Derived 类的 print() 方法
delete basePtr;
}

// 28. explicit 关键字:阻止隐式类型转换
class MyClass {
public:
explicit MyClass(int value) : value(value) {}
int getValue() const {
return value;
}
private:
int value;
};
void explicitExample() {
// MyClass obj = 10; // 错误:禁止隐式转换
MyClass obj(10); // 正确:显式调用构造函数
std::cout << "Value: " << obj.getValue() << std::endl;
}

// 29. friend 关键字:友元函数
class MyClass {
public:
friend void printValue(const MyClass& obj);
MyClass(int value) : value(value) {}
private:
int value;
};

void printValue(const MyClass& obj) {
std::cout << "Value: " << obj.value << std::endl;
}
void friendExample() {
MyClass obj(10);
printValue(obj);
}

// 30. sizeof 关键字:获取数据类型的大小
void sizeofExample() {
int num = 10;
std::cout << "Size of int: " << sizeof(num) << std::endl;
}

// 31. alignof 关键字:获取数据类型的对齐方式
void alignofExample() {
int num = 10;
std::cout << "Alignment of int: " << alignof(num) << std::endl;
}

// 32. noexcept 关键字:声明函数不会抛出异常
int add(int a, int b) noexcept {
return a + b;
}
void noexceptExample() {
int result = add(10, 20);
std::cout << "Result: " << result << std::endl;
}

int main() {
autoExample();
decltypeExample();
constexprExample();
lambdaExample();
defaultDeleteExample();
nullptrExample();
deprecatedExample();
numberSeparatorExample();
overrideExample();
finalExample();
staticCastExample();
reinterpretCastExample();
constCastExample();
dynamicCastExample();
typeidExample();
throwExample();
tryExample();
catchExample();
templateExample();
typenameExample();
operatorExample();
thisExample();
newExample();
deleteExample();
mutableExample();
inlineExample();
virtualExample();
explicitExample();
friendExample();
sizeofExample();
alignofExample();
noexceptExample();
return 0;
}

好的,很高兴继续演示 C++ 关键字。以下是一些其他重要的关键字,以及它们的用法和示例:

1. mutable

  • 用途:用于声明一个类成员变量,即使该成员变量所在的类对象是常量,也可以被修改。
  • 示例:
class MyClass {
public:
    mutable int count; // 即使 MyClass 对象是常量,count 也可以被修改
    void increment() {
        count++;
    }
};

int main() {
    const MyClass myObject; // myObject 是常量对象
    myObject.increment(); // 仍然可以调用 increment() 函数,修改 count
    return 0;
}

2. explicit

  • 用途:用于声明一个构造函数,防止它被用于隐式类型转换。
  • 示例:
class MyInt {
public:
    explicit MyInt(int value) : value(value) {}
    int value;
};

int main() {
    MyInt myInt1(10); // 正确的初始化方式
    // MyInt myInt2 = 10; // 错误,因为 MyInt 的构造函数被声明为 explicit
    return 0;
}

3. friend

  • 用途:用于声明一个函数或类为另一个类的友元,允许友元访问该类的私有成员。
  • 示例:
class MyClass {
private:
    int data;
public:
    friend void printData(MyClass obj); // 声明 printData 函数为 MyClass 的友元
};

void printData(MyClass obj) {
    std::cout << "Data: " << obj.data << std::endl; // 可以访问 MyClass 的私有成员 data
}

int main() {
    MyClass myObject;
    myObject.data = 10; // 错误,无法直接访问私有成员
    printData(myObject); // 可以通过友元函数访问私有成员
    return 0;
}

4. typeid

  • 用途:用于获取一个对象的类型信息。
  • 示例:
#include <typeinfo>

class MyClass {};

int main() {
    MyClass myObject;
    std::cout << "Type of myObject: " << typeid(myObject).name() << std::endl;
    return 0;
}

5. dynamic_cast

  • 用途:用于在运行时进行类型转换,如果转换失败,则返回 nullptr。
  • 示例:
#include <iostream>

class Base {
public:
    virtual void print() {
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void print() override {
        std::cout << "Derived class" << std::endl;
    }
};

int main() {
    Base *basePtr = new Derived();
    Derived *derivedPtr = dynamic_cast<Derived*>(basePtr); // 转换成功
    if (derivedPtr != nullptr) {
        derivedPtr->print(); // 调用 Derived 类中的 print() 函数
    }
    return 0;
}

6. reinterpret_cast

  • 用途:用于将一个指针转换为另一个类型的指针,不进行任何类型检查。
  • 示例:
int value = 10;
int *intPtr = &value;
char *charPtr = reinterpret_cast<char*>(intPtr); // 将 int 指针转换为 char 指针

7. const_cast

  • 用途:用于移除一个对象的常量性。
  • 示例:
const int value = 10;
int *intPtr = const_cast<int*>(&value); // 移除 value 的常量性
*intPtr = 20; // 可以修改 value 的值

8. static_cast

  • 用途:用于在编译时进行类型转换,可以用于将一个类型转换为另一个类型,但需要确保转换是安全的。
  • 示例:
double d = 3.14;
int i = static_cast<int>(d); // 将 double 转换为 int

9. sizeof

  • 用途:用于获取一个类型或变量的大小(以字节为单位)。
  • 示例:
int value = 10;
std::cout << "Size of int: " << sizeof(int) << std::endl;
std::cout << "Size of value: " << sizeof(value) << std::endl;

10. alignof

  • 用途:用于获取一个类型的对齐方式。
  • 示例:
std::cout << "Alignment of int: " << alignof(int) << std::endl;

11. noexcept

  • 用途:用于声明一个函数是否可能抛出异常。
  • 示例:
int add(int a, int b) noexcept { // 声明 add 函数不会抛出异常
    return a + b;
}

12. constexpr

  • 用途:用于声明一个常量表达式,可以在编译时计算。
  • 示例:
constexpr int square(int x) {
    return x * x;
}

int main() {
    constexpr int result = square(5); // 在编译时计算 result 的值
    std::cout << "Result: " << result << std::endl;
    return 0;
}

13. decltype

  • 用途:用于获取一个表达式的类型。
  • 示例:
int value = 10;
decltype(value) anotherValue = 20; // anotherValue 的类型为 int

14. nullptr

  • 用途:用于表示空指针。
  • 示例:
int *ptr = nullptr; // 初始化 ptr 为空指针

15. using

  • 用途:用于创建别名或将命名空间中的成员引入当前作用域。
  • 示例:
using MyInt = int; // 创建 MyInt 类型的别名
using namespace std; // 将 std 命名空间中的成员引入当前作用域

16. auto

  • 用途:用于自动推断变量的类型。
  • 示例:
auto value = 10; // value 的类型为 int

17. template

  • 用途:用于创建泛型函数或类。
  • 示例:
template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    int result1 = add(10, 20); // 调用 add 函数,类型为 int
    double result2 = add(3.14, 2.71); // 调用 add 函数,类型为 double
    return 0;
}

18. typename

  • 用途:用于在模板中指定一个类型。
  • 示例:
template <typename T>
class MyClass {
public:
    typename T::value_type value; // 使用 typename 指定 T::value_type 为一个类型
};

19. operator

  • 用途:用于声明运算符重载函数。
  • 示例:
class MyInt {
public:
    int value;
    MyInt(int value) : value(value) {}
    MyInt operator+(const MyInt &other) const {
        return MyInt(value + other.value);
    }
};

int main() {
    MyInt myInt1(10);
    MyInt myInt2(20);
    MyInt myInt3 = myInt1 + myInt2; // 使用 + 运算符重载函数
    std::cout << "myInt3.value: " << myInt3.value << std::endl;
    return 0;
}

20. namespace

  • 用途:用于定义命名空间,用于组织代码并避免命名冲突。
  • 示例:
namespace MyNamespace {
    int value = 10;
}

int main() {
    std::cout << "MyNamespace::value: " << MyNamespace::value << std::endl;
    return 0;
}

21. volatile

  • 用途:用于声明一个变量,即使该变量的值没有被显式修改,编译器也不应该对其进行优化。
  • 示例:
volatile int value = 0; // value 可能会被外部因素修改,例如硬件中断

int main() {
    while (true) {
        // ...
        value++; // 每次循环都读取 value 的值,即使它没有被修改
        // ...
    }
    return 0;
}

22. register

  • 用途:用于建议编译器将一个变量存储在寄存器中,以提高访问速度。
  • 示例:
register int i; // 建议将 i 存储在寄存器中
for (i = 0; i < 10; i++) {
    // ...
}

23. extern

  • 用途:用于声明一个变量或函数,其定义在其他文件中。
  • 示例:
// 在 file1.cpp 中
int value = 10;

// 在 file2.cpp 中
extern int value; // 声明 value 在其他文件中定义

24. inline

  • 用途:用于建议编译器将一个函数内联,以提高执行速度。
  • 示例:
inline int add(int a, int b) {
    return a + b;
}

25. virtual

  • 用途:用于声明一个虚函数,允许在派生类中重写该函数。
  • 示例:
class Base {
public:
    virtual void print() {
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void print() override { // 重写 Base 类中的 print 函数
        std::cout << "Derived class" << std::endl;
    }
};

26. override

  • 用途:用于声明一个函数重写了基类中的虚函数。
  • 示例:
class Base {
public:
    virtual void print() {
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void print() override { // 重写 Base 类中的 print 函数
        std::cout << "Derived class" << std::endl;
    }
};

27. final

  • 用途:用于声明一个类或函数不能被继承或重写。
  • 示例:
class Base final { // Base 类不能被继承
    // ...
};

class Derived : public Base { // 错误,Base 类不能被继承
    // ...
};

class Base {
public:
    virtual void print() final { // print 函数不能被重写
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void print() override { // 错误,print 函数不能被重写
        std::cout << "Derived class" << std::endl;
    }
};

28. delete

  • 用途:用于删除一个对象或释放内存。
  • 示例:
int *ptr = new int(10);
delete ptr; // 释放 ptr 指向的内存

29. new

  • 用途:用于动态分配内存。
  • 示例:
int *ptr = new int(10); // 分配一个 int 类型的大小,并初始化为 10

30. this

  • 用途:用于指向当前对象的指针。
  • 示例:
class MyClass {
public:
    int value;
    void print() {
        std::cout << "Value: " << this->value << std::endl; // 使用 this 指针访问成员变量
    }
};

31. operator new

  • 用途:用于重载 new 运算符,自定义内存分配方式。
  • 示例:
void* operator new(size_t size) {
    // 自定义内存分配逻辑
    return malloc(size);
}

int main() {
    int *ptr = new int(10); // 使用自定义的 new 运算符分配内存
    return 0;
}

32. operator delete

  • 用途:用于重载 delete 运算符,自定义内存释放方式。
  • 示例:
void operator delete(void *ptr) {
    // 自定义内存释放逻辑
    free(ptr);
}

int main() {
    int *ptr = new int(10);
    delete ptr; // 使用自定义的 delete 运算符释放内存
    return 0;
}

33. throw

  • 用途:用于抛出异常。
  • 示例:
#include <iostream>

int main() {
    try {
        throw std::runtime_error("Error occurred!");
    } catch (const std::exception &e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    }
    return 0;
}

34. try

  • 用途:用于捕获异常。
  • 示例:
#include <iostream>

int main() {
    try {
        throw std::runtime_error("Error occurred!");
    } catch (const std::exception &e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    }
    return 0;
}

35. catch

  • 用途:用于处理捕获的异常。
  • 示例:
#include <iostream>

int main() {
    try {
        throw std::runtime_error("Error occurred!");
    } catch (const std::exception &e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    }
    return 0;
}

36. goto

  • 用途:用于无条件跳转到程序中的另一个位置。
  • 示例:
int main() {
    int i = 0;
    loop:
    if (i < 10) {
        std::cout << i << std::endl;
        i++;
        goto loop;
    }
    return 0;
}

37. asm

  • 用途:用于嵌入汇编代码。
  • 示例:
int main() {
    asm("mov eax, 1"); // 嵌入汇编代码
    return 0;
}

38. __attribute__

  • 用途:用于添加函数或变量的属性。
  • 示例:
int myFunction() __attribute__((noreturn)); // 声明 myFunction 函数不会返回

39. __func__

  • 用途:用于获取当前函数的名称。
  • 示例:
void myFunction() {
    std::cout << "Function name: " << __func__ << std::endl;
}

40. __LINE__

  • 用途:用于获取当前代码行的行号。
  • 示例:
void myFunction() {
    std::cout << "Line number: " << __LINE__ << std::endl;
}

41. __FILE__

  • 用途:用于获取当前源文件的名称。
  • 示例:
void myFunction() {
    std::cout << "File name: " << __FILE__ << std::endl;
}

42. __DATE__

  • 用途:用于获取编译日期。
  • 示例:
int main() {
    std::cout << "Compilation date: " << __DATE__ << std::endl;
    return 0;
}

43. __TIME__

  • 用途:用于获取编译时间。
  • 示例:
int main() {
    std::cout << "Compilation time: " << __TIME__ << std::endl;
    return 0;
}

44. __cplusplus

  • 用途:用于检查当前编译器是否支持 C++。
  • 示例:
#ifdef __cplusplus
    std::cout << "C++ is supported" << std::endl;
#endif

45. __VA_ARGS__

  • 用途:用于在宏定义中访问可变参数。

46. sizeof 运算符

  • 用途:用于获取数据类型或变量的大小(以字节为单位)。
  • 示例:
#include <iostream>

int main() {
    int num = 10;
    std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
    std::cout << "Size of num: " << sizeof(num) << " bytes" << std::endl;
    return 0;
}

47. alignof 运算符

  • 用途:用于获取数据类型的对齐方式。
  • 示例:
#include <iostream>

int main() {
    int num = 10;
    std::cout << "Alignment of int: " << alignof(int) << std::endl;
    return 0;
}

在C++中,数据类型的对齐方式是编译器根据平台架构和优化考虑来决定如何在内存中排列数据。数据类型的对齐方式可以影响内存访问的效率和数据存储的紧凑性。以下是一些常见的数据类型对齐规则:

  1. 默认对齐

    • 在C++中,数据类型的默认对齐方式通常是按照其自身大小进行对齐。例如,char通常对齐到1字节,int对齐到4字节(32位系统)或8字节(64位系统)等。
  2. 结构体对齐

    • 结构体的对齐方式是按照结构体中最大成员的大小进行对齐。这样做是为了保证结构体的每个成员都能够被正确对齐,以提高访问效率。
    • 结构体的大小通常是其成员大小的倍数,但也受到编译器的优化和对齐规则的影响。
  3. 指定对齐方式

    • 可以使用#pragma pack(n)指令或__attribute__((packed))属性来指定结构体的对齐方式,将其设置为n字节对齐。这样可以控制结构体在内存中的紧凑性,但可能会影响访问效率。
  4. 对齐补齐

    • 为了满足对齐要求,编译器可能会在结构体成员之间插入填充字节(padding),使得结构体的起始地址和每个成员的地址都符合对齐要求。
    • 对齐补齐可以确保数据的访问效率,但可能会增加内存的占用。
  5. 数据类型对齐的优化

    • 在一些特定情况下,编译器可能会根据平台和编译选项进行数据类型对齐的优化,以提高程序的性能和效率。

假设有以下结构体定义:

#include <iostream>

struct MyStruct {
    char a;
    int b;
    double c;
};

int main() {
    std::cout << "Size of MyStruct: " << sizeof(MyStruct) << " bytes" << std::endl;
    return 0;
}

在这个示例中,MyStruct 结构体包含一个 char 类型的成员 a,一个 int 类型的成员 b,和一个 double 类型的成员 c

当运行这段代码时,会得到结构体 MyStruct 的大小。这个大小取决于结构体成员的大小和对齐方式。可以通过以下方式观察结构体成员在内存中的布局情况:

  1. char achar 类型通常占用1字节。
  2. int b:在大多数系统上,int 类型通常占用4字节。
  3. double cdouble 类型通常占用8字节。

根据默认对齐规则,结构体的对齐方式通常是按照最大成员的大小进行对齐。在这个例子中,double 类型的 c 成员是最大的,因此结构体 MyStruct 的大小可能会是 1(char) + 3(padding) + 4(int) + 8(double) = 16 字节。
好处:
访问效率提高:数据类型对齐可以提高内存访问的效率。当数据按照合适的边界对齐时,处理器可以更快地访问内存中的数据,因为它们可以直接从内存中读取对齐的数据,而无需额外的处理。

硬件要求:许多计算机体系结构要求数据按照特定的边界对齐,否则可能会导致性能下降甚至程序崩溃。

平台兼容性:正确对齐数据类型可以增加代码在不同平台上的可移植性,避免因为对齐问题导致程序在不同平台上表现不一致的情况。

内存空间利用:对齐数据类型可以减少内存碎片,提高内存空间的利用率。

坏处:
内存浪费:对齐数据类型可能会导致内存浪费。为了满足对齐要求,编译器可能会在数据类型之间插入填充字节,增加结构体或类的大小。

结构体大小增加:由于对齐要求,结构体或类的大小可能会比成员变量的总和更大,导致额外的内存消耗。

复杂性:手动控制数据类型的对齐可能会增加代码的复杂性,尤其是在需要处理不同平台的情况下。

数据类型对齐在提高访问效率和硬件兼容性方面带来了明显的好处,但在内存利用和复杂性方面可能会带来一些不利影响。通常情况下,编译器会根据平台架构和优化考虑自动处理数据类型的对齐,以平衡性能和内存利用率。

48. noexcept 关键字

  • 用途:用于声明一个函数不会抛出异常。
  • 示例:
#include <iostream>

int divide(int a, int b) noexcept {
    if (b == 0) {
        throw std::runtime_error("Division by zero");
    }
    return a / b;
}

int main() {
    try {
        int result = divide(10, 0);
        std::cout << "Result: " << result << std::endl;
    } catch (const std::runtime_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

49. throw 关键字

  • 用途:用于抛出异常。
  • 示例:
#include <iostream>
#include <stdexcept>

int divide(int a, int b) {
    if (b == 0) {
        throw std::runtime_error("Division by zero");
    }
    return a / b;
}

int main() {
    try {
        int result = divide(10, 0);
        std::cout << "Result: " << result << std::endl;
    } catch (const std::runtime_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

当然,这里是关于这些C++关键字的详细讲解:

27. consteval

consteval 关键字用来声明一个立即函数,表示这个函数在编译时就必须进行常量求值。这样确保函数在编译期就返回结果,不能在运行时调用。示例如下:

consteval int square(int n) {
    return n * n;
}

int main() {
    constexpr int result = square(5); // 正常,编译期计算
    // int result2 = square(5); // 错误,不能在运行时调用
    return 0;
}

29. constinit

constinit 关键字确保变量在程序启动时被静态初始化(即常量初始化)。如果没有这一关键字,可能会导致初始化顺序的问题。示例如下:

constinit int global_var = 42; // 确保在程序启动时静态初始化

int main() {
    return 0;
}

30. const_cast

const_cast 用于移除变量的const属性,或添加/移除volatile属性。它主要用于指针或引用的类型转换。示例如下:

void func(const int* p) {
    int* modifiable = const_cast<int*>(p);
    *modifiable = 10; // 允许修改值
}

int main() {
    const int a = 5;
    func(&a);
    return 0;
}

33. default

default 关键字主要用于在类的定义中显式声明默认构造函数、析构函数、拷贝构造函数、移动构造函数和赋值运算符。示例如下:

class MyClass {
public:
    MyClass() = default; // 使用默认构造函数
    ~MyClass() = default; // 使用默认析构函数
};

37. dynamic_cast

dynamic_cast 用于在运行时进行安全的多态类型转换。它通常用于将基类指针或引用转换为派生类指针或引用。示例如下:

class Base { virtual void func() {} };
class Derived : public Base { void func() override {} };

int main() {
    Base* b = new Derived;
    Derived* d = dynamic_cast<Derived*>(b); // 安全的转换
    return 0;
}

40. explicit

explicit 关键字用于修饰构造函数,防止它被隐式调用,从而避免隐式转换。示例如下:

class MyClass {
public:
    explicit MyClass(int x) {} // 防止隐式转换
};

int main() {
    MyClass obj1(10); // 正常
    // MyClass obj2 = 10; // 错误,隐式转换被禁止
    return 0;
}

41. export

export 关键字用于模板的导出,使模板定义与声明分离。但由于支持有限,这个关键字在实际中很少使用,并且在C++20中被移除了。

52. mutable

mutable 关键字用于允许在const成员函数中修改某些数据成员。示例如下:

class MyClass {
public:
    mutable int x;
    MyClass() : x(0) {}
    void modify() const { x = 10; } // 允许修改x
};

53. namespace

namespace 用于定义命名空间,以避免名字冲突。示例如下:

namespace MyNamespace {
    int value = 42;
}

int main() {
    int value = 0;
    value = MyNamespace::value; // 使用命名空间中的value
    return 0;
}

59. operator

operator 关键字用于重载运算符。示例如下:

class MyClass {
public:
    int value;
    MyClass(int v) : value(v) {}
    MyClass operator+(const MyClass& other) {
        return MyClass(value + other.value);
    }
};

int main() {
    MyClass a(5), b(10);
    MyClass c = a + b; // 使用重载的+运算符
    return 0;
}

63. protected

protected 访问修饰符允许派生类访问基类的成员,但外部代码不能访问。示例如下:

class Base {
protected:
    int value;
};

class Derived : public Base {
public:
    void setValue(int v) { value = v; }
};

int main() {
    Derived d;
    d.setValue(10); // 正常
    // d.value = 10; // 错误,不能直接访问protected成员
    return 0;
}

66. reinterpret_cast

reinterpret_cast 用于进行类型的低级别转换,一般用于不同指针类型之间的转换。它不会进行任何检查,所以需要谨慎使用。示例如下:

int main() {
    int a = 65;
    char* p = reinterpret_cast<char*>(&a); // 将int指针转换为char指针
    std::cout << *p << std::endl; // 输出'A',ASCII码为65
    return 0;
}

67. requires

requires 关键字用于定义C++20中的概念,来约束模板参数。它用于检查模板参数是否符合某些条件。示例如下:

template<typename T>
concept Incrementable = requires(T x) {
    x++;
};

template<Incrementable T>
void increment(T& x) {
    ++x;
}

int main() {
    int a = 5;
    increment(a); // 正常
    return 0;
}

70. signed

signed 关键字用于声明整数类型是有符号的。它是默认的,因此一般不需要显式使用。示例如下:

signed int a = -10; // 有符号整数
unsigned int b = 10; // 无符号整数

int main() {
    std::cout << a << " " << b << std::endl; // 输出-10 10
    return 0;
}

72. static

static 关键字有多种用途,包括:

  • 静态变量:在函数内部,静态变量在函数调用之间保留其值。
  • 静态成员:在类中,静态成员属于类而不是某个对象。
  • 静态函数:在类中,静态函数可以不依赖于对象实例调用。

示例如下:

void func() {
    static int count = 0; // 静态变量
    count++;
    std::cout << count << std::endl;
}

class MyClass {
public:
    static int static_value; // 静态成员变量
    static void static_func() { // 静态成员函数
        std::cout << "Static function" << std::endl;
    }
};

int MyClass::static_value = 0;

int main() {
    func(); // 输出1
    func(); // 输出2
    MyClass::static_value = 10;
    MyClass::static_func(); // 输出"Static function"
    return 0;
}

73. static_assert

static_assert 用于在编译时进行断言,如果条件不满足,编译器会生成错误。示例如下:

static_assert(sizeof(int) == 4, "int类型大小必须是4字节");

int main() {
    return 0;
}

74. static_cast

static_cast 用于进行显式类型转换,适用于常规类型转换,包括基本数据类型之间的转换和类层次结构中的向上转换和向下转换。示例如下:

int main() {
    double d = 3.14;
    int a = static_cast<int>(d); // 将double转换为int
    std::cout << a << std::endl; // 输出3
    return 0;
}

77. synchronized

synchronized 关键字并不是标准C++的一部分,而是Java中的关键字。在C++中,通常使用std::mutex和其他同步机制来实现线程同步。示例如下:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void print_thread_id(int id) {
    std::lock_guard<std::mutex> lock(mtx); // 自动管理锁的获取与释放
    std::cout << "Thread ID: " << id << std::endl;
}

int main() {
    std::thread t1(print_thread_id, 1);
    std::thread t2(print_thread_id, 2);
    t1.join();
    t2.join();
    return 0;
}

78. template

template 关键字用于定义模板,支持泛型编程,使得函数和类可以处理任意类型。示例如下:

template<typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    std::cout << add(3, 4) << std::endl; // 输出7
    std::cout << add(3.5, 4.5) << std::endl; // 输出8.0
    return 0;
}

80. thread_local

thread_local 关键字用于声明线程局部存储的变量,即每个线程都有其独立的变量副本。示例如下:

#include <iostream>
#include <thread>

thread_local int value = 0;

void print_value() {
    value++;
    std::cout << "Thread ID: " << std::this_thread::get_id() << ", Value: " << value << std::endl;
}

int main() {
    std::thread t1(print_value);
    std::thread t2(print_value);
    t1.join();
    t2.join();
    return 0;
}

84. typedef

typedef 用于为现有类型定义新的类型名。它可以使代码更加简洁和易读。示例如下:

typedef unsigned long ulong;

int main() {
    ulong a = 100;
    std::cout << a << std::endl; // 输出100
    return 0;
}

85. typeid

typeid 用于获取类型信息,通常与RTTI(运行时类型信息)一起使用。示例如下:

#include <iostream>
#include <typeinfo>

int main() {
    int a = 10;
    std::cout << "Type of a: " << typeid(a).name() << std::endl; // 输出int类型的信息
    return 0;
}

86. typename

typename 关键字用于模板中声明类型名称,通常用于表示依赖于模板参数的类型。示例如下:

template<typename T>
class MyClass {
public:
    typename T::value_type value; // 使用typename表示依赖类型
};

int main() {
    return 0;
}

C++多线程模型一般可以使用线程,也可以使用协程,具体选择取决于需求和应用场景。

线程模型

C++11引入了标准线程库,通过std::thread类可以轻松创建和管理线程。以下是一个简单的多线程示例:

#include <iostream>
#include <thread>

void printHello() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t(printHello);
    t.join(); // 等待线程结束
    std::cout << "Hello from main!" << std::endl;
    return 0;
}

协程模型

C++20引入了协程,协程是一种更加轻量级的并发方式。协程在执行期间可以被暂停和恢复,适用于处理异步任务。以下是一个简单的协程示例:

#include <iostream>
#include <coroutine>

struct Task {
    struct promise_type {
        Task get_return_object() { return {}; }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() {}
    };
};

Task example() {
    std::cout << "Start of coroutine" << std::endl;
    co_await std::suspend_always{};
    std::cout << "End of coroutine" << std::endl;
}

int main() {
    example();
    return 0;
}

选择线程还是协程

  • 线程:适用于CPU密集型任务、需要并行执行的独立任务。线程之间可以通过锁和条件变量进行同步。
  • 协程:适用于I/O密集型任务、需要处理大量异步操作的情况。协程的开销更低,可以提高资源利用率和响应速度。

选择线程还是协程取决于具体的应用场景和需求。如果需要处理大量并发I/O操作,可以优先考虑协程;如果任务需要并行处理且独立运行,则可以选择线程。

#include <iostream>

// 定义一个简单的模板类
template <typename T>
class Pair {
private:
    T first;
    T second;

public:
    Pair(T f, T s) : first(f), second(s) {}

    void display() {
        std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
    }
};

// 定义一个简单的模板函数
template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    // 实例化模板类 Pair,并展示其功能
    Pair<int> intPair(10, 20);
    intPair.display();

    Pair<double> doublePair(3.14, 2.71);
    doublePair.display();

    // 调用模板函数 add,并展示其功能
    int sumInt = add(5, 10);
    std::cout << "Sum of integers: " << sumInt << std::endl;

    double sumDouble = add(3.14, 2.71);
    std::cout << "Sum of doubles: " << sumDouble << std::endl;

    return 0;
}

在这个示例中,定义了一个模板类 Pair,它可以存储一对相同类型的值,并提供了一个 display 方法来显示这对值。还定义了一个模板函数 add,它可以对两个相同类型的值进行加法运算。

main 函数中,展示了如何实例化模板类 Pair 以处理不同类型的值,并调用模板函数 add 来处理不同类型的加法操作。

以下是一个简单的示例,演示了如何在 C++ 中使用线程和互斥锁(mutex)来实现多线程并发操作:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx; // 定义一个互斥锁

void printNumbers(int id) {
    mtx.lock(); // 加锁
    for (int i = 1; i <= 5; ++i) {
        std::cout << "Thread " << id << ": " << i << std::endl;
    }
    mtx.unlock(); // 解锁
}

int main() {
    // 创建两个线程并启动
    std::thread t1(printNumbers, 1);
    std::thread t2(printNumbers, 2);

    // 等待两个线程执行完毕
    t1.join();
    t2.join();

    return 0;
}

在这个示例中,首先包含了 <thread><mutex> 头文件,分别用于多线程和互斥锁的操作。

main 函数中,创建了两个线程 t1t2,它们都调用 printNumbers 函数,并传入不同的线程 ID。在 printNumbers 函数中,使用 std::mutex 定义了一个互斥锁 mtx,并在需要保护临界区的代码段前后使用 mtx.lock()mtx.unlock() 来实现对临界区的互斥访问。

当一个线程进入临界区并获得锁时,另一个线程会被阻塞,直到第一个线程释放锁。这样可以确保多个线程不会同时访问共享资源,避免数据竞争和不确定行为。

在本示例中,两个线程分别打印数字 1 到 5,由于使用了互斥锁,打印操作是依次进行的,而不会交叉进行。

在C++中,实现并发编程和多线程(也称携程)的常用方法包括使用标准库中的<thread><future>头文件。以下是详细的演示和讲解。

基本线程示例

在C++11中,可以使用std::thread来创建和管理线程。下面是一个简单的例子,演示如何创建和运行线程。

#include <iostream>
#include <thread>

// 线程函数
void hello() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    // 创建一个线程并执行函数hello
    std::thread t(hello);
    // 等待线程t完成
    t.join();
    return 0;
}

在这个例子中,创建了一个新的线程t,它运行函数hello,并在主线程中等待线程t完成。

带参数的线程函数

线程函数可以接受参数。以下是一个传递参数给线程函数的例子:

#include <iostream>
#include <thread>

// 带参数的线程函数
void print_number(int x) {
    std::cout << "Thread printing: " << x << std::endl;
}

int main() {
    int number = 42;
    // 创建一个线程并传递参数
    std::thread t(print_number, number);
    // 等待线程t完成
    t.join();
    return 0;
}

在这个例子中,线程函数print_number接受一个整数参数,并打印它的值。

使用std::mutex进行线程同步

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx; // 全局互斥锁

void print_with_lock(int x) {
    std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
    std::cout << "Thread printing with lock: " << x << std::endl;
}

int main() {
    std::thread t1(print_with_lock, 1);
    std::thread t2(print_with_lock, 2);

    t1.join();
    t2.join();
    return 0;
}

在这个例子中,std::lock_guard用于管理互斥锁的生命周期,确保在访问共享资源时只有一个线程可以执行。

使用std::futurestd::promise

C++11提供了std::futurestd::promise来实现线程之间的通信。std::promise用于在一个线程中设置值,std::future用于在另一个线程中获取值。以下是一个例子:

#include <iostream>
#include <thread>
#include <future>

// 计算平方的函数
void compute_square(std::promise<int>& p, int x) {
    int result = x * x;
    p.set_value(result); // 设置promise的值
}

int main() {
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();

    std::thread t(compute_square, std::ref(prom), 4);

    int result = fut.get(); // 获取计算结果
    std::cout << "The square is: " << result << std::endl;

    t.join();
    return 0;
}

在这个例子中,一个线程计算一个数的平方并将结果通过std::promise传递给主线程,主线程通过std::future获取结果。

使用std::async进行异步操作

std::async提供了一种简单的方法来启动异步任务并获取其结果。以下是一个例子:

#include <iostream>
#include <future>

// 计算平方的函数
int compute_square(int x) {
    return x * x;
}

int main() {
    // 异步调用compute_square
    std::future<int> fut = std::async(std::launch::async, compute_square, 4);

    int result = fut.get(); // 获取计算结果
    std::cout << "The square is: " << result << std::endl;

    return 0;
}

在这个例子中,std::async用于启动一个异步任务,并返回一个std::future对象,主线程可以通过该对象获取异步任务的结果。

使用std::condition_variable进行线程间的等待通知

std::condition_variable用于实现复杂的线程间同步机制。以下是一个生产者-消费者模型的例子:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> q;

void producer() {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        q.push(i);
        std::cout << "Produced: " << i << std::endl;
        cv.notify_one();
    }
}

void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return !q.empty(); });
        int item = q.front();
        q.pop();
        std::cout << "Consumed: " << item << std::endl;
        if (item == 9) break;
    }
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);

    t1.join();
    t2.join();
    return 0;
}

在这个例子中,生产者线程向队列中添加数据,并通知消费者线程。消费者线程等待通知并处理队列中的数据。

在C++中,有多种类型的锁可以用于同步多线程访问共享资源。这些锁包括std::mutexstd::recursive_mutexstd::timed_mutexstd::recursive_timed_mutexstd::shared_mutex(C++17引入)等。下面将详细演示这些锁的使用。

std::mutex

std::mutex是最基本的互斥锁,用于保护共享资源以避免数据竞态。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void print_number(int x) {
    std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
    std::cout << "Thread printing: " << x << std::endl;
}

int main() {
    std::thread t1(print_number, 1);
    std::thread t2(print_number, 2);

    t1.join();
    t2.join();
    return 0;
}

std::recursive_mutex

std::recursive_mutex允许同一个线程多次锁定互斥锁。

#include <iostream>
#include <thread>
#include <mutex>

std::recursive_mutex rec_mtx;

void recursive_function(int depth) {
    if (depth <= 0) return;
    rec_mtx.lock();
    std::cout << "Depth: " << depth << std::endl;
    recursive_function(depth - 1);
    rec_mtx.unlock();
}

int main() {
    std::thread t1(recursive_function, 5);

    t1.join();
    return 0;
}

std::timed_mutex

std::timed_mutex提供了尝试在一段时间内锁定互斥锁的功能。

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>

std::timed_mutex t_mtx;

void try_lock_for_seconds(int id, int seconds) {
    if (t_mtx.try_lock_for(std::chrono::seconds(seconds))) {
        std::cout << "Thread " << id << " acquired the lock." << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
        t_mtx.unlock();
    } else {
        std::cout << "Thread " << id << " failed to acquire the lock." << std::endl;
    }
}

int main() {
    std::thread t1(try_lock_for_seconds, 1, 1);
    std::thread t2(try_lock_for_seconds, 2, 2);

    t1.join();
    t2.join();
    return 0;
}

std::recursive_timed_mutex

std::recursive_timed_mutex结合了std::recursive_mutexstd::timed_mutex的功能,允许同一个线程多次锁定互斥锁,并提供尝试在一段时间内锁定的功能。

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>

std::recursive_timed_mutex rec_t_mtx;

void recursive_try_lock(int depth, int id) {
    if (depth <= 0) return;
    if (rec_t_mtx.try_lock_for(std::chrono::seconds(1))) {
        std::cout << "Thread " << id << " acquired lock at depth " << depth << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        recursive_try_lock(depth - 1, id);
        rec_t_mtx.unlock();
    } else {
        std::cout << "Thread " << id << " failed to acquire lock at depth " << depth << std::endl;
    }
}

int main() {
    std::thread t1(recursive_try_lock, 3, 1);
    std::thread t2(recursive_try_lock, 3, 2);

    t1.join();
    t2.join();
    return 0;
}

std::shared_mutex (C++17)

std::shared_mutex允许多个线程同时读取共享资源,但只有一个线程可以写入。这种锁在读多写少的场景中非常有用。

#include <iostream>
#include <thread>
#include <shared_mutex>
#include <vector>

std::shared_mutex sh_mtx;
std::vector<int> shared_data;

void reader(int id) {
    std::shared_lock<std::shared_mutex> lock(sh_mtx); // 共享锁
    std::cout << "Reader " << id << " is reading data:    for (int num : shared_data) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
}

void writer(int id, int value) {
    std::unique_lock<std::shared_mutex> lock(sh_mtx); // 独占锁
    shared_data.push_back(value);
    std::cout << "Writer " << id << " added value: " << value << std::endl;
}

int main() {
    std::thread t1(reader, 1);
    std::thread t2(writer, 2, 10);
    std::thread t3(reader, 3);

    t1.join();
    t2.join();
    t3.join();
    return 0;
}

当一个线程申请使用写锁(独占锁)时,如果同时有多个其他线程持有读锁(共享锁),写锁的申请将会被阻塞,直到所有读锁都被释放。读锁和写锁之间的关系是互斥的:

  1. 当一个线程持有写锁时,其他任何线程都不能获得读锁或写锁。
  2. 当一个或多个线程持有读锁时,任何线程都不能获得写锁。
#include <iostream>
#include <thread>
#include <shared_mutex>
#include <vector>
#include <chrono>

std::shared_mutex sh_mtx;
std::vector<int> shared_data;

void reader(int id) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟读取前的延迟
    std::shared_lock<std::shared_mutex> lock(sh_mtx); // 共享锁
    std::cout << "Reader " << id << " is reading data:    for (int num : shared_data) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
}

void writer(int id, int value) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟写入前的延迟
    std::unique_lock<std::shared_mutex> lock(sh_mtx); // 独占锁
    shared_data.push_back(value);
    std::cout << "Writer " << id << " added value: " << value << std::endl;
}

int main() {
    std::thread t1(reader, 1);
    std::thread t2(reader, 2);
    std::thread t3(writer, 3, 10);
    std::thread t4(reader, 4);

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    return 0;
}

预期行为:

  1. t1t2线程几乎同时开始读取操作,并持有共享锁。
  2. t3线程尝试获取独占锁(写锁),但由于t1t2持有共享锁,t3被阻塞。
  3. t1t2完成读取操作并释放共享锁后,t3才能获得写锁并进行写操作。
  4. t4线程在t3释放写锁后,才能继续持有共享锁并读取数据。

运行输出可能类似如下:

Reader 1 is reading data:Reader 2 is reading data:Writer 3 added value: 10
Reader 4 is reading data:10

在 C++ 中,类似于 Java 集合类的基本数据结构有许多选择,并且根据需要,可以选择线程安全或者线程不安全的实现。以下是一些主要的数据结构及其线程安全和线程不安全的实现方式:

1. std::vector

  • 线程不安全std::vector 是一个动态数组,支持随机访问和快速索引。
  • 线程安全:可以通过添加互斥锁(如 std::mutex)来保护 std::vector 的访问。
#include <vector>
#include <mutex>

std::vector<int> vec;
std::mutex mtx;

void safePushBack(int value) {
    std::lock_guard<std::mutex> lock(mtx);
    vec.push_back(value);
}

2. std::list

  • 线程不安全std::list 是一个双向链表,适用于频繁插入和删除操作。
  • 线程安全:同样可以使用互斥锁来保护对 std::list 的操作。
#include <list>
#include <mutex>

std::list<int> lst;
std::mutex mtx;

void safeAddToList(int value) {
    std::lock_guard<std::mutex> lock(mtx);
    lst.push_back(value);
}

3. std::setstd::unordered_set

  • 线程不安全std::set 是一个有序集合,std::unordered_set 是一个无序集合。
  • 线程安全:使用互斥锁来保护集合的修改。
#include <set>
#include <unordered_set>
#include <mutex>

std::set<int> orderedSet;
std::unordered_set<int> unorderedSet;
std::mutex mtx;

void safeInsertToSet(int value) {
    std::lock_guard<std::mutex> lock(mtx);
    orderedSet.insert(value);
    unorderedSet.insert(value);
}

4. std::mapstd::unordered_map

  • 线程不安全std::map 是一个有序键值对集合,std::unordered_map 是一个无序键值对集合。
  • 线程安全:使用互斥锁来保护对映射的修改。
#include <map>
#include <unordered_map>
#include <mutex>

std::map<int, int> orderedMap;
std::unordered_map<int, int> unorderedMap;
std::mutex mtx;

void safeInsertToMap(int key, int value) {
    std::lock_guard<std::mutex> lock(mtx);
    orderedMap[key] = value;
    unorderedMap[key] = value;
}

5. boost::thread_safe

Boost 库提供了线程安全的数据结构,例如 boost::thread_safe::map,可以直接使用而无需手动添加互斥锁。

#include <boost/thread_safe.hpp>

boost::thread_safe::map<int, int> threadSafeMap;

void safeInsertToBoostMap(int key, int value) {
    threadSafeMap[key] = value;
}

总结

在 C++ 中,实现线程安全的集合类通常依赖于使用互斥锁来保护数据结构的访问。此外,使用 Boost 库可以简化一些实现。选择具体的数据结构时,需根据实际应用场景来决定,并根据是否需要线程安全来添加相应的保护措施。

在C++中,可以使用标准库中的std::thread来创建和管理线程。下面将详细演示如何使用线程,包括线程的创建、同步、传递参数、返回值等方面。

基本线程创建

#include <iostream>
#include <thread>

void print_message(const std::string& message) {
    std::cout << "Message: " << message << std::endl;
}

int main() {
    std::thread t(print_message, "Hello, World!");
    t.join(); // 等待线程完成
    return 0;
}

线程同步

使用std::mutex进行线程同步,以避免数据竞态。

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>

std::mutex mtx;
std::vector<int> shared_data;

void add_to_vector(int value) {
    std::lock_guard<std::mutex> lock(mtx);
    shared_data.push_back(value);
    std::cout << "Added value: " << value << std::endl;
}

int main() {
    std::thread t1(add_to_vector, 1);
    std::thread t2(add_to_vector, 2);
    std::thread t3(add_to_vector, 3);

    t1.join();
    t2.join();
    t3.join();

    std::cout << "Vector size: " << shared_data.size() << std::endl;
    return 0;
}

传递参数给线程

可以通过值传递、引用传递、以及使用std::ref进行显式引用传递。

#include <iostream>
#include <thread>
#include <vector>

void modify_vector(std::vector<int>& vec) {
    for (auto& val : vec) {
        val *= 2;
    }
}

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5};
    std::thread t(modify_vector, std::ref(data));
    t.join();

    for (const auto& val : data) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
    return 0;
}

从线程返回值

可以使用std::promisestd::future来从线程返回值。

#include <iostream>
#include <thread>
#include <future>

int calculate_square(int x) {
    return x * x;
}

int main() {
    std::promise<int> promise;
    std::future<int> future = promise.get_future();

    std::thread t([&promise]() {
        int result = calculate_square(5);
        promise.set_value(result);
    });

    t.join();
    std::cout << "Result: " << future.get() << std::endl;
    return 0;
}

使用std::async

std::async可以简化线程创建和返回值处理。

#include <iostream>
#include <future>

int calculate_square(int x) {
    return x * x;
}

int main() {
    std::future<int> future = std::async(std::launch::async, calculate_square, 5);
    std::cout << "Result: " << future.get() << std::endl;
    return 0;
}

使用条件变量进行线程同步

条件变量(std::condition_variable)可以让线程等待某个条件的满足。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void print_id(int id) {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; });
    std::cout << "Thread " << id << std::endl;
}

void set_ready() {
    std::unique_lock<std::mutex> lock(mtx);
    ready = true;
    cv.notify_all();
}

int main() {
    std::thread t1(print_id, 1);
    std::thread t2(print_id, 2);

    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    set_ready();

    t1.join();
    t2.join();
    return 0;
}

这些例子展示了C++中如何使用线程、互斥锁、条件变量、以及如何传递参数和返回值。通过这些技术,可以构建并发和多线程程序,以充分利用多核处理器的性能。

Boost 库中的重点数据结构

Boost 库是一个广泛使用的 C++ 库集合,其中包含许多实用的工具和数据结构。以下是 Boost 库中一些重点数据结构,尤其是涉及线程安全的部分:

1. boost::thread_safe

Boost 线程安全数据结构库提供了一些内置的线程安全容器,简化了并发编程。这些容器包括线程安全的 mapset 等。

示例:boost::thread_safe::map
#include <boost/thread_safe/map.hpp>

boost::thread_safe::map<int, int> threadSafeMap;

void safeInsertToBoostMap(int key, int value) {
    threadSafeMap[key] = value;
}

2. boost::container

Boost 容器库提供了一些增强版的标准容器,例如 vectorlistmap 等,并且还包括一些标准库中没有的容器,例如 flat_map

示例:boost::container::flat_map

flat_map 是一种基于排序数组实现的关联容器,适用于键值对数量较少的情况,具有较好的缓存局部性。

#include <boost/container/flat_map.hpp>

boost::container::flat_map<int, int> flatMap;

void insertToFlatMap(int key, int value) {
    flatMap[key] = value;
}

3. boost::lockfree

Boost 锁自由数据结构库提供了一些不需要锁的并发数据结构,例如 queuestack,这些数据结构使用原子操作来保证线程安全。

示例:boost::lockfree::queue
#include <boost/lockfree/queue.hpp>
#include <atomic>

boost::lockfree::queue<int> lockFreeQueue(128); // 128 是队列容量
std::atomic<int> producerCount(0);
std::atomic<int> consumerCount(0);

void producer(int value) {
    if (lockFreeQueue.push(value)) {
        producerCount++;
    }
}

void consumer() {
    int value;
    if (lockFreeQueue.pop(value)) {
        consumerCount++;
    }
}

4. boost::intrusive

Boost 内嵌容器库提供了一些高效的容器,这些容器不管理元素的内存,而是将元素内嵌到容器中,适用于需要高性能和自定义内存管理的场景。

示例:boost::intrusive::list
#include <boost/intrusive/list.hpp>

using namespace boost::intrusive;

struct MyClass : public list_base_hook<> {
    int value;
    MyClass(int v) : value(v) {}
};

typedef list<MyClass> List;
List myList;

void addToList(MyClass &obj) {
    myList.push_back(obj);
}

在这段代码中,void addToList(MyClass &obj) 函数中的 &obj 是一个引用(reference)类型的参数。引用是 C++ 中的一种数据类型,允许在函数中使用原始数据而不是副本,从而避免不必要的内存开销和提高性能。

具体来说,&obj 表示函数 addToList 接受一个指向 MyClass 类型对象的引用。当传递一个对象给这个函数时,实际上是传递了这个对象的引用,而不是对象的副本。这意味着在函数内部对 obj 的任何修改都会影响到原始对象,因为直接操作的是原始对象而不是它的副本。

使用引用作为函数参数通常有以下几个优点:

  1. 避免不必要的对象拷贝,提高性能。
  2. 允许函数修改传递进来的对象。
  3. 可以用来实现返回多个值的函数。

5. boost::multi_index

Boost 多重索引库允许在同一个容器中使用多个不同的索引方法,例如通过键值索引、通过排序索引等。

示例:boost::multi_index_container
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>

using namespace boost::multi_index;

struct Employee {
    int id;
    std::string name;
    Employee(int i, std::string n) : id(i), name(n) {}
};

typedef multi_index_container<
    Employee,
    indexed_by<
        ordered_unique<member<Employee, int, &Employee::id>>,
        ordered_non_unique<member<Employee, std::string, &Employee::name>>
    >
> EmployeeContainer;

EmployeeContainer employees;

void addEmployee(int id, std::string name) {
    employees.insert(Employee(id, name));
}

总结

C++中的lambda表达式是匿名函数,用于简洁地定义和使用函数对象。它们在C++11标准中引入,并在C++14和C++17中得到了进一步增强。下面通过几个示例详细演示lambda表达式的使用。

基本Lambda表达式

#include <iostream>

int main() {
    auto greet = []() {
        std::cout << "Hello, World!" << std::endl;
    };
    greet(); // 调用lambda表达式
    return 0;
}

带参数的Lambda表达式

#include <iostream>

int main() {
    auto add = [](int a, int b) {
        return a + b;
    };
    int result = add(3, 4);
    std::cout << "3 + 4 = " << result << std::endl;
    return 0;
}

捕获外部变量

Lambda表达式可以捕获外部作用域的变量,有多种捕获方式:按值捕获、按引用捕获。

按值捕获
#include <iostream>

int main() {
    int x = 10;
    auto print_x = [x]() {
        std::cout << "x = " << x << std::endl;
    };
    x = 20; // 修改x的值
    print_x(); // 打印的仍是捕获时的x值
    return 0;
}
按引用捕获
#include <iostream>

int main() {
    int x = 10;
    auto print_x = [&x]() {
        std::cout << "x = " << x << std::endl;
    };
    x = 20; // 修改x的值
    print_x(); // 打印的是修改后的x值
    return 0;
}

捕获所有变量

可以使用=&捕获所有变量,分别表示按值捕获和按引用捕获。

#include <iostream>

int main() {
    int x = 10;
    int y = 20;

    auto print_all_by_value = [=]() {
        std::cout << "x = " << x << ", y = " << y << std::endl;
    };

    auto print_all_by_reference = [&]() {
        std::cout << "x = " << x << ", y = " << y << std::endl;
    };

    x = 30;
    y = 40;

    print_all_by_value(); // 打印捕获时的值
    print_all_by_reference(); // 打印修改后的值
    return 0;
}

Lambda与STL算法

Lambda表达式非常适合与STL算法一起使用,例如std::for_eachstd::sort等。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 使用lambda表达式打印vector中的元素
    std::for_each(vec.begin(), vec.end(), [](int n) {
        std::cout << n << " ";
    });
    std::cout << std::endl;

    // 使用lambda表达式对vector进行排序(降序)
    std::sort(vec.begin(), vec.end(), [](int a, int b) {
        return b < a;
    });

    // 打印排序后的vector
    std::for_each(vec.begin(), vec.end(), [](int n) {
        std::cout << n << " ";
    });
    std::cout << std::endl;

    return 0;
}

可变Lambda(mutable)

默认情况下,lambda表达式不能修改捕获的变量。如果需要修改,可以使用mutable关键字。

#include <iostream>

int main() {
    int x = 10;
    auto increment_x = [x]() mutable {
        x++;
        std::cout << "x inside lambda = " << x << std::endl;
    };

    increment_x(); // 修改并打印x
    std::cout << "x outside lambda = " << x << std::endl; // x的值未变
    return 0;
}

Lambda作为线程的任务

Lambda表达式可以用于创建线程任务,非常简洁。

#include <iostream>
#include <thread>

int main() {
    int x = 10;

    std::thread t([x]() {
        std::cout << "Thread x = " << x << std::endl;
    });

    t.join(); // 等待线程完成
    return 0;
}

Lambda作为函数参数

Lambda表达式可以作为函数参数传递,用于回调函数等场景。

#include <iostream>
#include <vector>
#include <algorithm>

void apply_function(const std::vector<int>& vec, const std::function<void(int)>& func) {
    for (int n : vec) {
        func(n);
    }
}

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    apply_function(vec, [](int n) {
        std::cout << n << " ";
    });
    std::cout << std::endl;

    return 0;
}

这些示例展示了lambda表达式在C++中各种场景下的应用,包括基本用法、捕获变量、与STL结合、线程任务以及作为函数参数等。通过灵活使用lambda表达式,可以编写更加简洁和高效的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/766510.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学习springAOP

第三章 Spring AOP 第一节 AOP 简介 1. 概念 AOP全称为Aspect Oriented Programming&#xff0c;表示面向切面编程。何为切面呢&#xff1f; 由此可以得出&#xff0c;切面是一种将那些与业务无关&#xff0c;但业务模块都需要使用的功能封装起来的技术。这样便于减少系统的…

three.js地理坐标系有哪些,和屏幕坐标系的转换。

坐标系很好理解&#xff0c;就是点线面体的位置&#xff0c;一个点是一个坐标&#xff0c;一条线段2个坐标&#xff0c;一个矩形四个坐标&#xff0c;一个立方体8个坐标&#xff0c;three.js面对的是三维空间&#xff0c;屏幕则是二维的&#xff0c;这就面临着转换问题&#xf…

【Python机器学习系列】建立决策树模型预测小麦品种(案例+源码)

这是我的第314篇原创文章。 一、引言 对于表格数据&#xff0c;一套完整的机器学习建模流程如下&#xff1a; 针对不同的数据集&#xff0c;有些步骤不适用&#xff0c;其中橘红色框为必要步骤&#xff0c;欢迎大家关注翻看我之前的一些相关文章。前面我介绍了机器学习模型的二…

grpc编译 helloworld

【1】打开helloworld所在目录 examples\cpp\helloworld 【2】CMAKE生成会报错 【3】问题解决&#xff1a;增加环境变量path “C:\Program Files (x86)\grpc\bin” 是上一篇grpc编译后安装的目录 【4】CMAKE后直接用“Open Project”打开项目

Java关于标准输入和标准输出的理解

java中的标准输入指的是System.in还是键盘输入&#xff1f;概念搞不太清楚&#xff0c;用Scanner类从键盘输入算是标准输入吗&#xff1f; 先理清一些概念&#xff1a;每个控制台程序都有标准输入、标准输出、标准错误输出三个管道&#xff08;句柄&#xff09;&#xff0c;这…

【FFmpeg】avcodec_open2函数

目录 1. avcodec_open21.1 编解码器的预初始化&#xff08;ff_encode_preinit & ff_decode_preinit&#xff09;1.2 编解码器的初始化&#xff08;init&#xff09;1.3 释放编解码器&#xff08;ff_codec_close&#xff09; FFmpeg相关记录&#xff1a; 示例工程&#xff…

Python数据分析-房价预测机器学习

一、研究背景 房地产市场作为经济活动的关键领域之一&#xff0c;对于经济的发展和社会的稳定起着至关重要的作用。在当今全球化和信息化的背景下&#xff0c;房地产市场的波动和房价的变化不仅受到国内因素的影响&#xff0c;还受到全球经济环境和国际政治形势等外部因素的影…

深入理解ThreadLocal原理

以下内容首发于我的个人网站&#xff0c;来这里看更舒适&#xff1a;https://riun.xyz/work/9898775 ThreadLocal是一种用于实现线程局部变量的机制&#xff0c;它允许每个线程有自己独立的变量&#xff0c;从而达到了线程数据隔离的目的。 基于JDK8 使用 通常在项目中是这样…

JS爬虫实战之Fastmoss

Fastmoss参数逆向 逆向前准备思路1- 确认接口2- 参数确认3- 重试校验参数逻辑4- 寻找逆向入口1- 方式一&#xff08;search搜索&#xff09;&#xff1a;2- 方式二&#xff08;堆栈搜索&#xff09;&#xff1a; 5- 获取加密算法1- fm-sign字段是有zn来的&#xff0c;我们查看z…

机器学习 C++ 的opencv实现SVM图像二分类的训练 (二)【附源码】

本节讲机器学习 C 的opencv实现SVM图像二分类的训练&#xff0c;下节讲测试&#xff1a; 数据集合data内容如下&#xff1a; 下载地址为&#xff1a;https://download.csdn.net/download/hgaohr1021/89506900 #include <stdio.h> #include <time.h> #include…

C语言课程回顾:六、C语言循环控制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 C语言循环控制 6 循环控制6.1 概述6.2 goto语句以及用goto语句构成循环6.3 while语句6.4 do-while语句6.5 for语句6.6 循环的嵌套6.7 几种循环的比较6.8 break和continue语句…

Windows系统安装NVM,实现Node.js多版本管理

目录 一、前言 二、NVM简介 三、准备工作 1、卸载Node 2、创建文件夹 四、下载NVM 五、安装NVM 六、使用NVM 1、NVM常用操作命令 2、查看NVM版本信息 3、查看Node.js版本列表&#xff1b; 4、下载指定版本Node.js 5、使用指定版本Node.js 6、查看已安装Node.js列…

Java知识点整理 18 — Lambda表达式

一. 简介 Lambda 表达式是函数式编程思想的体现&#xff0c;强调做什么&#xff0c;而不是以什么方式去做。 面向对象编程思想强调的是对象&#xff0c;必须通过对象的形式来做一些事情。比如多线程执行任务&#xff0c;需要创建对象&#xff0c;对象需要实现指定接口&#x…

Rust监控可观测性

可观测性 在监控章节的引言中&#xff0c;我们提到了老板、前端、后端眼中的监控是各不相同的&#xff0c;那么有没有办法将监控模型进行抽象、统一呢&#xff1f; 来简单分析一下&#xff1a; 业务指标实时展示&#xff0c;这是一个指标型的数据( metric )手机 APP 上传的数…

若依 ruoyi vue上传控件 el-upload上传文件 判断是否有文件 判断文件大小

console.info(this.$refs.upload.uploadFiles.length)//this.$refs.upload.uploadFiles.length 获取当前上传控件中已选择的文件大小//判断是否存在已上传文件 if(this.$refs.upload.uploadFiles.length 0){this.$modal.msgWarning("请上传文件");return; }

轻松配置,无需重复操作:PyCharm新建项目后,如何让当前新建项目使用既有虚拟环境

1、点击右上角的设置按钮 2、点击Settings 3、点击profect 4、点击python Interprter&#xff0c;这个是python解释器 5、点击 add interpreter&#xff0c;这个是增加python解释器 6、再点击add Local interpreter 7、选择第一个Virtualenv Environment,然后选择Existin…

交叉编译tslib库和上机测试

目录 一、tslib 介绍 二、tslib 框架分析 三、交叉编译、测试 tslib 1.安装工具链 tslib &#xff08;1&#xff09;设置交叉编译工具链 &#xff08;2&#xff09;进入tslib目录 &#xff08;3&#xff09;安装工具链 &#xff08;4&#xff09;确定工具链中头文件、库…

Linux源码阅读笔记09-进程NICE案例分析1

task_nice task_nice函数功能&#xff1a;获取某个进程的nice值&#xff0c;其中nice值为进程的优先级&#xff0c;与静态优先级有关&#xff08;nicestatic_prio-120&#xff09;。 nice的取值范围&#xff1a;-20 ~ 19 内核源码 根据内核的注释可以知道&#xff1a;task_n…

13-Django项目--文件上传

目录 前端展示 路由: 数据库字段: 函数视图: 前端展示 {% extends "index/index.html" %}{% block content %}<div class"container"><input type"button" id"btnAdd" value"上传荣耀" class"btn btn-succ…

鼠标点击器免费版?详细介绍鼠标连点器的如何使用

随着科技的发展&#xff0c;鼠标连点器逐渐成为了我们生活和工作中不可或缺的工具。它不仅能够帮助我们完成频繁且重复的点击任务&#xff0c;还能在很大程度上减少我们的手部疲劳&#xff0c;提高工作效率。本文将详细介绍鼠标连点器的使用方法&#xff0c;并推荐三款好用的免…