懒加载
懒加载(Lazy Initialization 或 Lazy Loading)是一种设计模式或编程技巧,它的核心思想是:延迟初始化资源,只有在真正需要的时候才创建或加载这些资源。 懒加载的特点 避免不必要的开销 如果资源加载非常耗时或占用大量内存,懒加载可以减少程序启动时的资源占用。 提升性能 只有在资源被真正需要时才加载,减少了程序的启动时间。 按需加载 资源是否加载取决于程序运行时的实际需求,可能避免加载某些资源。 懒加载的使用场景 单例模式 在单例模式中,实例对象通常会在第一次访问时才创建。 例如,你的 Logger 类的实现:1234Logger &Logger::instance() { static Logger logger; // 静态变量只在第一次调用时初始化 return logger;} Logger 对象只有在调用 Logger::instance()...
仿函数
在 C++ 中,仿函数(Function Object 或 Functor) 是一种行为类似于函数的对象。仿函数是通过重载 operator() 运算符来实现的,这样一个对象就可以像函数一样调用。 仿函数的核心思想是:对象可以具有类似函数的行为,并且可以携带状态。这为设计灵活的函数调用方式提供了可能性,尤其是在 STL(标准模板库)中,仿函数被广泛应用于算法、容器操作等场景。 1. 仿函数的基本概念仿函数是通过在一个类中重载 operator() 运算符来实现的。这样,类的对象就可以被调用(表现得像一个函数)。 仿函数的基本语法12345678910111213141516#include <iostream>using namespace std;class MyFunctor {public: // 重载 operator() void operator()(int x) { cout << "Called with: " << x << endl; ...
可调用对象的绑定器和包装器
在 C++ 中,可调用对象的绑定器和包装器是用来简化或增强对函数(包括普通函数、成员函数、函数对象、Lambda 表达式等)的调用操作的工具。它们广泛用于泛型编程和 STL 算法中,以便将函数灵活地传递给算法或动态控制其行为。 1. 可调用对象的绑定器绑定器的作用是将一个可调用对象的一部分参数提前绑定,从而生成一个新的可调用对象。 C++11 起引入了 std::bind,用于创建一个可调用对象并绑定部分参数;在现代 C++(C++20)中,更推荐使用 Lambda 表达式 替代 std::bind。 1.1 std::bindstd::bind 是一个函数模板,它可以接受一个可调用对象(如普通函数、成员函数、函数对象等)及部分参数,并返回一个新的可调用对象,该对象可以像函数一样调用。 语法123#include <functional> // std::bind 所在的头文件std::bind(callable, arg1, arg2, ..., argN); callable:要绑定的可调用对象。 arg1, arg2, ...,...
模板
模板(Template)概述模板是 C++ 中的一种泛型编程机制,允许编写通用的代码,可以在不指定具体数据类型的情况下定义函数、类或结构体。模板的主要目的是提供代码的复用性和灵活性,从而支持处理多种数据类型的能力。 C++ 中的模板主要分为两种: 函数模板(Function Template) 类模板(Class Template) 1. 函数模板函数模板是定义一个可以操作多种数据类型的函数。通过模板,函数可以在调用时根据传递的参数类型自动生成具体的函数。 1.1 函数模板的基本语法12345678910template <typename T>T add(T a, T b) { return a + b;}int main() { cout << add<int>(3, 4) << endl; // 显式指定类型为 int cout << add(3.5, 4.2) << endl; // 隐式推导类型为 double return...
c++中的线程
在 C++ 中,线程是用来实现并发编程的重要工具,它允许程序同时执行多个任务。C++11 标准引入了多线程支持,主要通过 <thread> 标头文件提供相关功能,包括线程创建、管理和同步等。 1. 基本概念 线程是程序执行的基本单位,一个程序可以包含多个线程。 多线程可以提高程序效率,特别是在多核 CPU 上,每个线程可以在不同的核上运行。 C++ 提供的多线程功能包括: 线程的创建与管理(std::thread)。 同步机制(如互斥锁 std::mutex、条件变量 std::condition_variable 等)。 数据保护(如线程安全的操作)。 2. 创建和管理线程1) 创建线程线程可以通过 std::thread 创建,并且可以使用函数、lambda 表达式或可调用对象作为线程入口。 (a) 使用普通函数123456789101112#include <iostream>#include <thread>void threadFunction() { std::cout <<...
智能指针
智能指针是一种在编程中管理动态内存资源的对象。它封装了原始指针(raw pointer),并提供额外的功能,例如自动释放资源、避免内存泄漏和管理对象的生命周期。智能指针广泛用于需要动态分配内存的语言(如 C++),通过 RAII(Resource Acquisition Is Initialization)原则实现内存管理。 在 C++ 中,智能指针主要在 <memory> 头文件中定义,包括以下几种类型: 1. std::unique_ptr 特点: 独占所有权(一个对象只能有一个 unique_ptr 拥有它)。 不可复制,但可以通过 std::move 转移所有权。 适合需要明确单一所有权的场景。 用法: 12345678#include <memory>#include <iostream>int main() { std::unique_ptr<int> ptr = std::make_unique<int>(42); // 创建智能指针 std::cout <<...
Lambda表达式
在 C++ 中,Lambda 表达式是一种轻量级的函数对象(或匿名函数),可以在代码中定义并直接使用。它是从 C++11 引入的功能,常用于需要定义短小函数的场景,比如多线程、STL 算法或回调函数中。 1. Lambda 表达式的基本语法123[捕获列表](参数列表) -> 返回类型 { 函数体}; **捕获列表**:定义 lambda 可以捕获哪些变量,以及如何捕获(按值或按引用)。 **参数列表**:和普通函数类似,定义函数的参数。 **返回类型**:可选,通常由编译器自动推断。 **函数体**:函数的逻辑部分。 2. Lambda 表达式的基本示例12345678910111213141516171819#include <iostream>#include <vector>#include <algorithm>int main() { // 最简单的 Lambda auto lambda = [] { std::cout <<...
c++11新特性之emplace
emplace 是 C++ 中标准库(STL)提供的一种高效的元素插入方式,常用于容器(如 std::vector, std::map, std::unordered_map 等)中。emplace 通过直接在容器内部构造元素,避免了不必要的拷贝或移动操作,从而提高了性能。 emplace 和 insert 的区别 **insert**:将一个已构造的对象插入到容器中。通常需要通过拷贝或移动构造将元素插入容器。 123std::vector<int> vec;int x = 5;vec.insert(vec.end(), x); // 插入时会发生一次拷贝构造 **emplace**:直接在容器内部构造元素,避免了额外的拷贝或移动操作。emplace 接受构造元素所需的参数,然后直接在容器中构造该元素。 12std::vector<int> vec;vec.emplace_back(5); // 在容器内部构造元素,避免拷贝 为什么使用 emplace? 避免不必要的拷贝或移动: insert...
c++中的I/O流
在 C++ 中,输入输出(I/O)库提供了流(stream)的状态管理功能。每个流对象(如 cin, cout, ifstream, ofstream 等)都有一个与之相关的状态,标志着当前流的操作是否成功。流的状态主要通过流的条件标志(flags)来表示。这些标志通常用于检查流是否处于有效的状态,以便在进行输入输出操作时处理异常或错误。 流的条件状态(Flags)流的条件状态通过 ios 类中的几个成员标志进行管理,这些标志包括: **good()**:流是否处于正常状态,即没有发生任何错误。 **eof()**:流是否已经到达文件末尾。 **fail()**:流是否遇到输入/输出错误。 **bad()**:流是否发生严重错误,导致无法继续读取或写入。 这些状态标志可以通过流对象的方法访问,通常用于判断流的状态。 流的状态检查1. good() good() 返回 true 如果流没有遇到任何错误,输入输出操作可以继续进行。它相当于检查流的状态是否为 ios::goodbit。 123if (cin.good()) { cout...
c++中的四种命名的强制类型转换
在 C++ 中,有四种强制类型转换操作符,分别是: static_cast dynamic_cast const_cast reinterpret_cast 这四种类型转换都属于强制类型转换,值得一提的是其实这四种强制转换都是较为危险的,很容易出现错误,尽量少用 1. static_caststatic_cast 用于在类型之间进行转换时,进行编译时类型检查。 它适用于转换那些在语义上兼容的类型,例如基本数据类型、类之间的转换等。 任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast 用法: 类之间的转换(如父类和子类的转换)。 基本数据类型之间的转换。 指针类型之间的转换,当有继承关系时,可以转换指向基类的指针和指向派生类的指针。 示例:12345678910111213141516171819202122232425#include <iostream>//类之间的转换class Base {public: virtual void show() { std::cout <<...