Skip to content

零散的笔记素材

这里一般用来存放在日常代码编写中遇到问题 - 查找资料的过程中学习到的知识点,由于这些知识点往往非常重要但是暂时又不知到应该放在哪里,所以使用这个文件来临时存放直到找到它们应该被记录的位置。

基于范围的 for 循环详解

基于范围的 for 循环是 C++11 引入的简化遍历容器(如数组、std::vectorstd::map 等)的语法。它提供了一种简单、直接的方式来访问容器中的元素,避免了传统 for 循环中手动管理索引或迭代器的麻烦。

基本语法

c++
for (declaration : expression) {
    // 循环体
}
  • declaration:循环中每次迭代时用来表示容器中单个元素的变量。
  • expression:表示一个容器或范围(如数组、std::vector它提供一系列可遍历的元素。

使用示例

假设我们有一个 std::vector 容器,可以通过基于范围的 for 循环来遍历数组中的每个元素:

c++
#include <iostream>
#include <vector>

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

    // 使用基于范围的 for 循环遍历
    for (int v : vec) {
        std::cout << v << " "; // 输出:1 2 3 4 5
    }

    return 0;
}

在这个例子中,int v 表示 vec 中的每个元素,而 vec 是要遍历的容器。

遍历数组

基于范围的 for 循环同样适用于 C++ 的内置数组:

c++
int arr[5] = {10, 20, 30, 40};

for (int v : arr) {
    std::cout << v << " "; // 输出:10 20 30 40
}

TIP

建议使用 auto 让编译器自动推导类型,auto& 表示对元素的引用,减少手动编写类型声明的繁琐和可能的错误。

放下 C 语言余孽,拥抱 C++ 特性

c++
ios::sync_with_stdio(0); cin.tie(0),; cout.tie(0);

别惦记你那 printf/scanf 啦,这三个语句可用于优化 C++cincout 的输入输出性能,使得 C++IO流与 C 的 stdio 达到几乎一致的速度的同时,兼顾了 C++ 一贯的稳定性。它们的作用分别如下:

  1. ios::sync_with_stdio(false):
    • 这一语句用于禁用 C++ 的 iostream 与 C 语言的 stdio 的同步。
    • 默认情况下,C++ 的 cin/cout 与 C 语言的 scanf/printf 是同步的,以确保它们可以混合使用。然而,这种同步操作会带来额外的性能开销。
    • 设置 ios::sync_with_stdio(false) 可以提升 cincout 的输入输出效率,但一旦禁用了同步,cin/coutscanf/printf 不应混合使用,否则可能会出现输出顺序错乱或其他问题。
  2. cin.tie(0):
    • tie() 函数用于控制输入输出流之间的绑定关系。
    • 默认情况下,cincout 是绑定的,即每次使用 cin 输入时,都会自动刷新 cout 缓冲区,确保 cout 输出的内容是最新的。
    • 通过调用 cin.tie(0),可以解开这种绑定,使 cincout 之间的刷新机制解除,从而提升性能,尤其是在大量输入输出操作时。这样可以减少不必要的缓冲区刷新,从而提高运行速度。
  3. cout.tie(0):
    • cin.tie(0) 类似,这个语句用于解绑 cout 与其他流(通常是 cin)的关系。

vector.emplace_back()

  • emplace_back 是 C++11 引入的 std::vector 的成员函数。它的作用是在容器的末尾直接构造一个元素,而不是先创建一个对象再拷贝或移动到容器中。它的主要优势在于避免不必要的拷贝或移动操作,提高效率。
  • emplace_back 直接在容器的内存空间中构造元素。相比于 push_back,它避免了创建临时对象的开销。适用于构造复杂对象或自定义类型对象的场景,因为可以传递构造对象所需的参数。
  • 对于自定义类型,emplace_back 也非常有用,因为它可以直接传递构造函数的参数:

Lambda 表达式

Lambda 表达式是一种用于定义匿名函数的方式,可以在局部范围内创建一个没有名称的函数对象。它的基本语法如下:

c++
[capture](parameters) -> return_type { body }
  • [capture]:捕获列表,用于指定 lambda 表达式中可以使用的外部变量。特别地,& 表示按引用捕获外部作用域中的所有变量。
  • (parameters):参数列表,类似于普通函数的参数列表。
  • -> return_type:返回类型,可以省略,编译器会自动推导。
  • { body }:函数体,包含 lambda 表达式的代码。

使用

  • 可选地,在 lambda 表达式后面的 () 表示对这个 lambda 表达式的调用。相当于直接执行这个匿名函数。

  • 如果 lambda 表达式没有立即被调用,你可以将其存储在一个变量中,并在稍后的代码中根据需要多次调用。这种方式在 C++ 中非常灵活,可以用于多种场景,比如延迟执行、回调函数、函数对象等。下面是一些使用方法:

    1. 存储到变量中并调用

    你可以将 lambda 表达式赋值给一个变量,然后在程序的其他地方调用它:

    c++
    #include <iostream>
    
    int main() {
        // 将 lambda 表达式存储在变量中
        auto printMessage = []() {
            std::cout << "Hello, World!" << std::endl;
        };
    
        // 在后面需要的时候调用它
        printMessage(); // 输出: Hello, World!
        printMessage(); // 可以多次调用
        return 0;
    }

    2. 作为函数参数

    你可以将 lambda 表达式作为参数传递给另一个函数。

    3. 返回值为 Lambda 表达式

    你可以编写一个函数,返回一个 lambda 表达式供后续调用:

    c++
    #include <iostream>
    
    auto createMultiplier(int factor) {
        return [factor](int x) { return x * factor; };
    }
    
    int main() {
        auto doubleValue = createMultiplier(2); // 创建一个将值乘以2的 lambda
        auto tripleValue = createMultiplier(3); // 创建一个将值乘以3的 lambda
    
        std::cout << doubleValue(5) << std::endl; // 输出: 10
        std::cout << tripleValue(5) << std::endl; // 输出: 15
    
        return 0;
    }