C++ 关键字与库函数 学习总结

news2024/9/19 10:37:05

sizeof与strlen

  • 含义
    • sizeof:是一个操作符,用于计算数据类型或变量的大小(以字节为单位)。在编译时求值
    • strlen: 是一个函数,用于计算字符串的长度(不包括终止符 '\0')。在运行时求值
  • 不同点
    • 计算时间strlen是库函数,程序运行时计算长度;sizeof则是在编译时计算长度
    • 计算方式:sizeof包括终止符号 \0 。strlen则不包括,只计算字符串的实际长度
  • 两者的返回类型都是size_t类型

#include <stdio.h>

int main() {
    int a = 10;
    double b = 20.0;
    char c = 'A';
    char str[] = "Hello, World!";

    printf("Size of int: %zu bytes\n", sizeof(a));              // 输出变量 a 的大小
    printf("Size of double: %zu bytes\n", sizeof(b));          // 输出变量 b 的大小
    printf("Size of char: %zu bytes\n", sizeof(c));            // 输出变量 c 的大小
    printf("Size of string: %zu bytes\n", sizeof(str));        // 输出数组 str 的大小,包括终止符 '\0'

    return 0;
}

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, World!";
    
    printf("Length of string: %zu characters\n", strlen(str));  // 输出字符串 str 的长度,不包括终止符 '\0'
    
    return 0;
}

 static

C和C++中都可以用static去定义静态变量以及静态函数,因为C++是面向对象编程,所以还可以使用static去定义静态成员变量以及静态成员函数等。

static全局和局部静态变量

static 全局静态变量

  • 全局静态变量是在文件范围内定义的,并且只能在定义它的文件中访问。它在程序的整个生命周期内都存在,但它的作用域仅限于定义它们的文件
  • static全局静态变量,则只可以在定义所在文件中有效,同一个程序中的其他源文件不可以使用。

static局部静态变量

  • 局部静态变量是在函数内部定义的,并且只能在定义它们的函数中访问
  • 存储在静态存储区中,生命周期是贯穿在整个程序的运行期间

static全局静态变量和static局部静态变量区别总结 

  • 作用域

    • 全局静态变量:仅限于定义它的文件中
    • 局部静态变量:仅限于定义它们的函数
  • 生命周期

    • 全局静态变量:在程序的整个生命周期内都存在。
    • 局部静态变量:在程序的整个生命周期内都存在,但它的值在函数调用之间保留
  • 存储位置

    • 全局静态变量:存储在静态数据区
    • 局部静态变量:存储在静态数据区,而不是栈区
    • 两者都存储静态数据区中

// 全局静态变量
static int global_static_var = 0;

void increment_global_static_var() {
    global_static_var++;
    printf("全局静态变量: %d\n", global_static_var);
}

int main() {
    increment_global_static_var(); // 输出:1
    increment_global_static_var(); // 输出:2
    return 0;
}

 

#include <stdio.h>

void increment_local_static_var() {
    // 局部静态变量
    static int local_static_var = 0;
    local_static_var++;
    printf("局部静态变量: %d\n", local_static_var);
}

int main() {
    increment_local_static_var(); // 输出:1
    increment_local_static_var(); // 输出:2
    increment_local_static_var(); // 输出:3
    return 0;
}

static静态函数 

 static静态函数

  • 作用域:只可以在定义该函数的文件内部调用,不可以从其他文件中访问该函数
  • 作用:定义的函数只放在该文件中使用,避免命名造成的冲突

 代码说明:两段代码是放在不同的文件

static静态成员变量 

static静态成员变量

  •  声明:类内声明,类外定义初始化。可以通过类名直接访问,不需要创建对象
  • 作用域:静态成员变量在整个进程生命周期内都存在
  • 特点
    • 共享性:所有类对象共享一个静态成员变量
    • 静态成员变量可以作为成员函数的参数,普通成员变量不可以
    • 静态成员变量的类型可以用该类自己的类型,而普通成员变量只可以用该类的指针或者引用
    • 唯一性:无论创建多少对象,静态成员变量在内存中只占用同一块内存空间

#include <iostream>

class MyClass {
public:
    // 静态成员变量声明
    static int staticVar;

    // 成员函数,用于显示静态成员变量的值
    void display() const {
        std::cout << "Static Variable: " << staticVar << std::endl;
    }
};

// 静态成员变量定义(注意记忆)
int MyClass::staticVar = 0;

int main() {
    // 通过类名访问静态成员变量
    MyClass::staticVar = 5;

    MyClass obj1;
    MyClass obj2;

    obj1.display(); // 输出:Static Variable: 5
    obj2.display(); // 输出:Static Variable: 5

    // 修改静态成员变量的值
    MyClass::staticVar = 10;

    obj1.display(); // 输出:Static Variable: 10
    obj2.display(); // 输出:Static Variable: 10

    return 0;
}

 static静态成员函数

static静态成员函数

  •  作用域:静态成员函数是没有this指针的,所以不可以调用非静态成员或者非静态成员函数,可以类内声明类外定义
  • 特点
    • 静态成员函数是类作用域的全局函数
    • 静态成员函数不可以声明成virtual const volatile函数
    • 独立:静态成员函数是独立于任何对象的,因为不可以访问类的非静态成员变量或非静态成员函数
  • 优点
    • 静态成员中可以封装与对象无关的逻辑,从而实现类内共享
    • 静态成员函数不需要创建对象就可以调用,所以可以节省内存资源

#include <iostream>

class MyClass {
public:
    // 静态成员函数声明
    static void staticFunction();

    // 非静态成员函数声明
    void nonStaticFunction() {
        std::cout << "This is a non-static member function.\n";
    }

private:
    int nonStaticVar; // 非静态成员变量
};

  static对象

 static对象

  • 静态全局对象:整个程序运行期间存在,但是其作用域只限于定义它的文件中
  • 静态局部对象:函数内定义,只可以在定义它的作用域中访问,第一次调用的时候初始化,在程序的整个生命周期都保留该数值,不会再次初始化。
  • 类的静态成员对象:每个类只拥有一个静态成员对象的实例,并且所有对象共享这个对象
#include <iostream>

static int globalStaticVar = 0; // 静态全局对象

void incrementGlobalStaticVar() {
    globalStaticVar++;
    std::cout << "Global static variable: " << globalStaticVar << std::endl;
}

int main() {
    incrementGlobalStaticVar(); // 输出:Global static variable: 1
    incrementGlobalStaticVar(); // 输出:Global static variable: 2
    return 0;
}
#include <iostream>

void incrementLocalStaticVar() {
    static int localStaticVar = 0; // 静态局部对象
    localStaticVar++;
    std::cout << "Local static variable: " << localStaticVar << std::endl;
}

int main() {
    incrementLocalStaticVar(); // 输出:Local static variable: 1
    incrementLocalStaticVar(); // 输出:Local static variable: 2
    incrementLocalStaticVar(); // 输出:Local static variable: 3
    return 0;
}
#include <iostream>

class MyClass {
public:
    static MyClass staticInstance; // 静态成员对象声明

    void display() const {
        std::cout << "This is a static member object." << std::endl;
    }
};

// 静态成员对象定义
MyClass MyClass::staticInstance;

int main() {
    MyClass::staticInstance.display(); // 通过类名访问静态成员对象

    MyClass obj;
    obj.staticInstance.display(); // 通过对象访问静态成员对象(不推荐)

    return 0;
}

const

总结:

  • const常量:const修饰变量或者成员变量,可以进行类型检查,从而节省内存空间提高效率
  • const函数参数:传递过来函数参数的数值不可以改变
  • const成员函数:该成员函数不可以修改任何类型的成员变量(mutable修饰的变量可以),同时该函数不可以调用非const的成员函数

const 变量

const 变量

  • 全局const变量:整个程序色生命周期存在,不可以修改,其他文件通过extern声明也可以访问
  • 局部const变量:函数或代码块中定义,只可以在定义的作用域中访问
  • 类的const成员变量:类中声明的const成员变量,必须在构造函数初始化列表中进行初始化
#include <iostream>

const int globalConstVar = 100; // 全局 const 变量

int main() {
    std::cout << "全局 const 变量: " << globalConstVar << std::endl;
    // globalConstVar = 200; // 错误:不能修改 const 变量
    return 0;
}
#include <iostream>

void displayLocalConst() {
    const int localConstVar = 50; // 局部 const 变量
    std::cout << "局部 const 变量: " << localConstVar << std::endl;
    // localConstVar = 100; // 错误:不能修改 const 变量
}

int main() {
    displayLocalConst();
    return 0;
}
#include <iostream>

class MyClass {
public:
    const int memberConstVar; // 类的 const 成员变量

    MyClass(int val) : memberConstVar(val) {} // 在构造函数初始化列表中初始化

    void display() const {
        std::cout << "类的 const 成员变量 " << memberConstVar << std::endl;
    }
};

int main() {
    MyClass obj(10);
    obj.display();
    // obj.memberConstVar = 20; // 错误:不能修改 const 成员变量
    return 0;
}

const指针和指向const的指针

const指针和指向const的指针

  • 指向const的指针:指针指向的值不可以通过指针对该值进行修改,但是指针本身可以改变
  • const指针:指针本身是常量,不能够改变指向,但是指向的数值可以修改
  • 指向const的const指针:指针本身和指针指向都不可以修改
  • 注意:两种写法不同,注意记忆

#include <iostream>

int main() {
    int value = 30;
    const int* ptr = &value; // 指向 const 的指针
    std::cout << "Value: " << *ptr << std::endl;
    // *ptr = 40; // 错误:不能通过 ptr 修改值
    int anotherValue = 50;
    ptr = &anotherValue; // 可以改变指针本身
    std::cout << "Another value: " << *ptr << std::endl;
    return 0;
}
#include <iostream>

int main() {
    int value = 30;
    int* const ptr = &value; // const 指针
    std::cout << "Value: " << *ptr << std::endl;
    *ptr = 40; // 可以修改指向的值
    std::cout << "Modified value: " << *ptr << std::endl;
    // int anotherValue = 50;
    // ptr = &anotherValue; // 错误:不能改变指针本身
    return 0;
}
#include <iostream>

int main() {
    int value = 50;
    const int* const ptr = &value; // 指向 const 的 const 指针
    std::cout << "Value: " << *ptr << std::endl;
    // *ptr = 60; // 错误:不能修改指向的值
    // int anotherValue = 70;
    // ptr = &anotherValue; // 错误:不能改变指针本身
    return 0;
}

const引用 

const引用:const引用指向const对象的应用,可以读取变量,但是不可以通过应用修改指向的数值

#include <iostream>

void display(const int& ref) {
    std::cout << "Reference: " << ref << std::endl;
    // ref = 20; // 错误:不能通过 const 引用修改值
}

int main() {
    int value = 10;
    display(value);
    return 0;
}

define 和 const

define 和 const

  • 含义
    • #define 是一个预处理指令,用于定义宏。编译之前,预处理器会用宏的值替换程序中的所有宏名。没有类型检查,也不会在调试信息中出现
    • const 是一个关键字,用于定义类型安全的常量变量。const 变量在程序运行期间受类型检查,并且可以用于更复杂的数据类型,如数组、指针和对象
  • 特点:
    • 编译阶段:define是在编译预处理阶段进行替换,没有时间开销。const则是在编译阶段确定数值,会有时间开销。
    • 安全性:define只是进行简单的代码替换,不会进行类型安全检查;const定义的常量是由类型,所以会进行类型安全检查
    • 存储空间:define浪费空间,程序每次替换的时候都会在内存中备份,替换越多备份越多 ;const节省空间,因为存储在静态区。
    • 调试:define定义的宏不可以调试,预编译阶段已经替换了。const定义的常量可以进行调试
    • define可以接受参数构造复杂的表达式,const不可以接受参数构造复杂的表达式。

inline

  • 含义
    • inline关键字用于提示编译器将函数定义为内联函数,内联函数的目的在于减少函数调用的开销从而提高程序的运行效率
    • 内联函数代码会在每次调用的时候直接插入到调用点,避免函数调用不必要的开销,内联只是一个建议,编译器可以选择忽略它
  • 特点
    •  减少函数调用开销:inline是一个关键字,像普通的函数一样被调用,而不是直接在调入点直接展开,从而减少调用函数带来的开销,提高程序运行效率
  • 使用
    • 类内定义成员函数默认就是内联函数,虚函数除外(虚函数运行时决定,编译时无法确定的虚函数的实际调用)
    • 类外定义成员函数,需要加上inline关键字

 

#include <iostream>

class MyClass {
public:
    inline void display() {
        std::cout << "内联函数运行" << std::endl;
    }
};

int main() {
    MyClass obj;
    obj.display();
    return 0;
}

new  malloc  delete free

malloc 

malloc 

  • 含义:该库函数用于动态分配内存,运行的时候从堆内存中分配指定大小的字节,并返回指向该内存块的指针。malloc分配的内存未初始化,所以内部的数据不确定

原理分析

  • 进程启动后,操作系统会给该进程分配一个初始的堆区域,同时初始化一个数据结构(此处按照链表梳理)
  • 第一次调用malloc的时候,内存管理器再空闲链表中查找一个足够大的空间,然后分配,如果失败则返回null
  • 是进程调用free的时候,内存管理器释放该链表所占用的内存空间

#include <stdio.h>
#include <stdlib.h>

int main() {
    int* ptr;
    ptr = (int*)malloc(10 * sizeof(int)); // 分配10个整数大小的内存
    if (ptr == NULL) {
        printf("Memory allocation failed\n");
        return 1;
    }

    for (int i = 0; i < 10; i++) {
        ptr[i] = i * 10;
    }

    for (int i = 0; i < 10; i++) {
        printf("%d ", ptr[i]);
    }

    free(ptr); // 释放内存
    return 0;
}

new 和 malloc的区别 

new 和 malloc的区别

  • 初始化:new申请内存时,会调用对象的构造函数,然后对对象初始化;malloc会在堆中申请一块指定大小的内存空间,仅分配内存,不会初始化
  • new指定内存空间初始化对象,malloc只可以在堆中申请内存
  • new是C++的操作符malloc是C中的一个函数
  • 返回值:new返回值是一个对象的指针类型malloc则返回void*指针
  • 空间大小:new的空间大小是由编译器自动计算的,malloc是需要指定其空间大小new的空间大小不可以改变

#include <iostream>

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

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

int main() {
    // 使用 new 分配单个对象
    MyClass* obj = new MyClass();
    
    // 使用 delete 释放内存
    delete obj;

    // 使用 new 分配数组
    MyClass* arr = new MyClass[3];
    
    // 使用 delete[] 释放数组内存
    delete[] arr;

    return 0;
}

#include <iostream>
#include <cstdlib>

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

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

int main() {
    // 使用 malloc 分配内存
    MyClass* obj = (MyClass*)malloc(sizeof(MyClass));
    // 需要手动调用构造函数
    new (obj) MyClass(); // 使用定位 new 调用构造函数

    // 使用 free 释放内存前需要手动调用析构函数
    obj->~MyClass();
    free(obj);

    // 使用 malloc 分配数组
    MyClass* arr = (MyClass*)malloc(3 * sizeof(MyClass));
    // 需要手动调用构造函数
    for (int i = 0; i < 3; ++i) {
        new (&arr[i]) MyClass(); // 使用定位 new 调用构造函数
    }

    // 使用 free 释放数组内存前需要手动调用析构函数
    for (int i = 0; i < 3; ++i) {
        arr[i].~MyClass();
    }
    free(arr);

    return 0;
}

delete和free的区别 

delete和free的区别

  • delete是C++的一个操作符,可以进行重载;free是C中的一个函数,不可以进行重载
  • free只会释放指向的内存,不会执行对象的析构函数;delete则可以执行对象的析构函数
  • delete和delete[ ] 
    • 释放 newnew[ ]分配的内存
    • 适当new分配的单个对象,释放new[ ] 分配的数组
  • free
    • 用法:释放malloc 、calloc 、realloc分配的内存
    • 仅释放内存,不调用析构函数

volatile

含义

  • 该关键字用于修饰变量,告诉编译器该变量在程序运行期间可能被改变,因为贬义词不能够对这个变量进行优化,需要每次访问该变量的时候都重新获取其数值

volatile的作用

  • 阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回
  • 阻止编译器调整操作volatile变量的指令排序

volatile使用场景分析

  •  多线程编程:volatile变量可以被多个线程修改,使用该关键字从而确保每个线程从内存中读取最新的数值,而不是从寄存器或者缓存中读取的旧值

限制

  • 非线程安全:该关键字可以确保每次读取变量的时候都是从内存中获取的最新值,但是不保证其原子性,所以在多线程中,需要使用互斥锁或者原子操作来保证其线程安全
  • 不适合硬件优化:如果CPU缓存或者其他硬件优化,则需要使用其他方式,内存栅栏(memory barriers)或 C++11 中的 std::atomic
//多线程场景下的使用

#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>

volatile bool stopFlag = false;

void worker() {
    while (!stopFlag) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    std::cout << "Worker thread exiting." << std::endl;
}

int main() {
    std::thread t(worker);

    std::this_thread::sleep_for(std::chrono::seconds(1));
    stopFlag = true;

    t.join();
    return 0;
}

使用宏实现比较大小以及两个数的最小值

#include <iostream>
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
using namespace std;

int main ()
{
    int var1 = 10, var2 = 100;
    cout << MAX(var1, var2) << endl; //100
    cout << MIN(var1, var2) << endl; //10
    return 0;
}


 宏定义和内联函数的区别 

 宏定义和内联函数的区别

  • 内联函数在编译的时候展开,宏则在编译预处理的时候展开;
  • 内联函数展开后是嵌入到代码中,宏只是进行简单的文本替换
  • 内联函数是真正的函数会对参数类型以及语句进行检查
  • 内联函数在调用点直接展开避免函数参数压栈,减少开销
  • 宏只是简单的对文本进行替换,所以容易出错
  • 内联函数可以调试宏函数无法调试

使用场景分析

  • 宏:定义简单的常量和轻量级的宏功能,负责的宏避免使用
  • 内联函数:内联函数比宏更安全且容易调试和维护

C和C++中的struct区别

含义

  • C语言中:struct 主要用于将多个不同类型的数据组合在一起形成一个复合数据类型。结构体中的成员默认是公开的(public),但它们不支持方法、构造函数、析构函数和访问控制
  • 在C++ 中:struct 保留了 C 中的所有特性,但它增加了许多新的功能,使其更接近于类(class)。在 C++ 中,struct 可以包含成员函数、构造函数、析构函数、访问控制和继承等特性。默认情况下,struct 的成员是公开的(public),而 class 的成员是私有的(private)

两者区别总结

  • 数据类型不同:C语言中是用户自定义的数据类型,C++中则是抽象数据类型,支持成员函数定义
  • 访问权限不同:C语言中的没有访问权限设置,不能够定义成员函数;C++中的struct和类一样,由访问权限可以定义成员函数
  • 定义变量:C语言中定义struct类型的变量时,需要加上struct关键字,但是C++ 中的struct可以不加关键字
  • 继承与多态:C++中的可以继承也可以对应实现多态

struct与union区别

  • 内存空间:union联合体中的所有变量共享同一段内存空间,struct中的每个成员变量独占内存空间
  • 成员:联合体只有一个有效成员(内部是有多个不同数据成员组成),结构体中的所有成员都有效
  • 成员赋值:联合体不同成员赋值的时候,会覆盖其他成员的值,但是对于结构体给不同成员赋值,则不会影响
  • 内存大小:联合体的大小是所有变量的最大值,按照最大值类型的倍数进行分配大小;结构体则是按照内存对齐原则
  • struct可以定义变长数组成员变量 int a [] ,union中不可以包含这种不确定长度的变量

//struct
#include <stdio.h>

struct Point {
    int x;
    int y;
};

int main() {
    struct Point p;
    p.x = 10;
    p.y = 20;
    printf("Point: (%d, %d)\n", p.x, p.y);
    return 0;
}

//union事例
#include <stdio.h>

union Data {
    int i;
    float f;
    char str[20];
};

int main() {
    union Data data;
    data.i = 10;
    printf("data.i: %d\n", data.i);

    data.f = 220.5;
    printf("data.f: %f\n", data.f);

    // 注意:此时访问 data.i 会得到未定义的值
    printf("data.i: %d\n", data.i); // 由于 union 共用内存,data.i 的值已被 data.f 覆盖

    return 0;
}

//混合使用
#include <stdio.h>

struct Mixed {
    int type;
    union {
        int intValue;
        float floatValue;
        char strValue[20];
    } data;
};

int main() {
    struct Mixed m;
    m.type = 0; // 表示 int 类型
    m.data.intValue = 10;
    printf("Type: %d, IntValue: %d\n", m.type, m.data.intValue);

    m.type = 1; // 表示 float 类型
    m.data.floatValue = 220.5;
    printf("Type: %d, FloatValue: %f\n", m.type, m.data.floatValue);

    m.type = 2; // 表示字符串类型
    snprintf(m.data.strValue, 20, "Hello, World!");
    printf("Type: %d, StrValue: %s\n", m.type, m.data.strValue);

    return 0;
}

extern C的作用

含义

  • extern C是一个链接规范,指示编译器按照C语言的方式处理被包含的代码
  • 目的是解决C++和C兼容性的问题,尤其在链接阶段
  • 让C++编译器生成与C兼容的符号名,从而让C++代码可以调试C代码

事例(一个用C写的函数,一个CPP代码,采用C的方式连接)

// c_code.c
#include <stdio.h>

void c_function() {
    printf("This is a C function.\n");
}
// cpp_code.cpp
#include <iostream>

// 告诉编译器按 C 语言的方式链接 c_function
extern "C" void c_function();

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

strcpy函数缺陷

  • 作用
    • C++中的一个标准函数,其会将函数' \0' 结束符的字符串复制到另一个地址空间,返回值的类型为char*,返回值为拷贝后的字符串首地址
  • 缺陷
    • 缓冲区溢出:不检查目的缓冲区的大小边界,而是将源字符串逐一全部复制到到新内存空间中,同时加上字符串的终止符号,但是这种行为会导致其他变量被覆盖
    • 不安全复制:如果源字符串没有以空字符 \0 结尾,那么strcpy就会一直复制,直到内存中的随机空字符
  • 避免缺陷
    • 使用strncpy 代替
      • strcpy的安全版本,允许指定最大复制的字符数,从而防止缓冲区的溢出
      • 如果源字符串长度大于指定的最大字符数,目标字符串将不会自动添加空字符
    • 动态内存分配

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "This is a long string that will not cause buffer overflow";
    char dest[10];

    strncpy(dest, src, sizeof(dest) - 1);
    dest[sizeof(dest) - 1] = '\0'; // 确保目标字符串以空字符结尾

    printf("Destination: %s\n", dest);
    return 0;
}

lambda 表达式

  • capture:用于捕获外部变量,可以按值捕获(=)或按引用捕获(&)。
  • parameters:函数参数列表,与普通函数相同。
  • return_type:返回类型(可选,如果编译器能推断出返回类型,则可以省略)。
  • function body:函数的具体实现

 基本lambda表示使用

#include <iostream>

int main() {
    auto add = [](int a, int b) -> int {
        return a + b;
    };

    int result = add(3, 4);
    std::cout << "Result: " << result << std::endl;

    return 0;
}

 捕捉外部变量

#include <iostream>

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

    // 按值捕获(复制变量)
    auto addValueCapture = [x, y]() {
        return x + y;
    };

    // 按引用捕获(引用变量)
    auto addReferenceCapture = [&x, &y]() {
        return x + y;
    };

    std::cout << "Value Capture: " << addValueCapture() << std::endl;
    std::cout << "Reference Capture: " << addReferenceCapture() << std::endl;

    return 0;
}

 捕捉所有外部变量

#include <iostream>

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

    // 按值捕获所有外部变量
    auto addAllValueCapture = [=]() {
        return x + y;
    };

    // 按引用捕获所有外部变量
    auto addAllReferenceCapture = [&]() {
        return x + y;
    };

    std::cout << "All Value Capture: " << addAllValueCapture() << std::endl;
    std::cout << "All Reference Capture: " << addAllReferenceCapture() << std::endl;

    return 0;
}

实现排序 

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

int main() {
    std::vector<int> numbers = {5, 2, 9, 1, 5, 6};

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

    std::cout << "Sorted numbers: ";
    for (int n : numbers) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

C++14 

C++14,lambda函数形参允许泛型和初始化捕捉

 C++14中,lanbda表达式支持泛型参数,从而使得可以编写类型无关的lambda表达式

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

int main() {
    auto add = [](auto a, auto b) {
        return a + b;
    };

    std::cout << "Sum of integers: " << add(1, 2) << std::endl; // 输出 3
    std::cout << "Sum of doubles: " << add(1.5, 2.3) << std::endl; // 输出 3.8
    std::cout << "Concatenation of strings: " << add(std::string("Hello, "), std::string("World!")) << std::endl; // 输出 Hello, World!

    return 0;
}

初始化捕捉:允许在捕获列表中直接初始化捕获的变量。主要作用在于捕捉并初始化一个新的变量时无需定义一个临时变量 

#include <iostream>

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

    auto lambda = [z = x + y]() {
        std::cout << "Captured sum: " << z << std::endl;
    };

    lambda(); // 输出 Captured sum: 30

    return 0;
}

explicit

explicit关键字用于C++的构造函数中,用于防止隐式转换

#include <iostream>
using namespace std;

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

    void printValue() const {
        cout << "Value: " << m_value << endl;
    }

private:
    int m_value;
};

void display(MyClass obj) {
    obj.printValue();
}

int main() {
    MyClass obj1(10); // 正确,显式调用构造函数
    obj1.printValue();

    // MyClass obj2 = 20; // 错误,隐式转换被explicit阻止
    MyClass obj2 = MyClass(20); // 正确,显式调用构造函数
    obj2.printValue();

    display(obj1); // 正确,显式调用
    // display(30); // 错误,隐式转换被explicit阻止
    display(MyClass(30)); // 正确,显式调用构造函数

    return 0;
}

define和typedef

define是一个预处理指令,用于定义符号常量和宏,编译前,预处理器用定义的值替换调代码中的符号

#include <iostream>
#define PI 3.14159
#define SQUARE(x) ((x) * (x))

int main() {
    std::cout << "Value of PI: " << PI << std::endl;
    std::cout << "Square of 5: " << SQUARE(5) << std::endl;
    return 0;
}

typedef:为现有的类型创建一个新名称

#include <iostream>

typedef unsigned long ulong;
typedef int (*func_ptr)(int, int);

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

int main() {
    ulong myNumber = 1000;
    std::cout << "Value of myNumber: " << myNumber << std::endl;

    func_ptr fptr = add;
    std::cout << "Sum of 3 and 4: " << fptr(3, 4) << std::endl;

    return 0;
}

 两者比较

  • define:用于定义符号常量和宏,预处理阶段替换,代码可读性差
  • typedef:为类型创建别名,在编译阶段进行替换,代码可读性较好

class和struct

两者区别

  • 默认访问权限:class成员默认是私有的,struct成员默认是公有的
  • 使用场景:class通常用于定义复杂的数据结构和具有成员函数对象,struct则反之
//注意,struct也可以定义公有、私有、保护成员
struct ExampleStruct {
    int publicValue; // 公有成员

private:
    int privateValue; // 私有成员

protected:
    int protectedValue; // 保护成员
};

sizeof(1==1)在C和C++中结果分析

1==1在C和C++结果不同的原因

  • 本质上是一个比较操作符,判断两个整数是否相等,所以在C和C++中返回的是一个布尔值
  • C中的布尔值是用int类型表示,所以1==1则返回1
  • C++在C++98标准开始,有自己的专属bool类型,所以会返回true

sizeof(1==1)

  • C中sizeof(1==1) 等价于 sizeof(int),因为int类型大小是4字节,所以最终结果是4
  • C++中布尔类型占有1个字节,所以返回结果为1

memmove函数

memmove

  • C标准库的函数,用于在内存中移动数据,比memcpy更安全,因为它处理了重叠区域情况
  • 作用:将原地址所指向的某个内存区域中的数据复制到目标地址所指向的另一个内存区域中
  • 参数解释
    • dest:目标内存指针
    • src:源内存指针
    • n:复制字节数
  • 返回值:返回dest

原理简析

  • 内部检查源地址和目标地址是否重叠,如果重叠则会从src的末尾开始复制,以避免覆盖源数据 

 

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, World!";
    printf("Original string: %s\n", str);

    // 使用 memmove 进行重叠内存区域的移动
    memmove(str + 7, str, 6); // 将 "Hello," 移动到 " World!" 之前
    printf("After memmove: %s\n", str);

    return 0;
}

auto

auto(自动类型推导,编译器根据初始化表达式的类型来推导变量类型)

#include <vector>
#include <iostream>

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

    // 使用 auto 来简化迭代器声明
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }

    return 0;
}

推导规则总结

  • 等式后是引用,则取出引用;如果auto后有&,则不去除
  • 顶层的const会被去除

new

new用于动态分配内存,为对象或者的数据类型分配相应的内存,并返回指向该内存的指针。new不仅分配内存,还调用构造函数来初始化对象

  • new和delete原理分析
    • new分配内存的时候,会调用操作系统的内存分配函数(一般情况下是malloc),然后返回指向分配内存的指针
    • new然后使用构造函数来初始化对象
    • delete释放内存的时候,调用对象的析构函数,然后调用操作系统内存释放函数
  • 注意
    • 内存泄漏:每次使用完new分配的内存后必须使用delete释放,否则会导致内存泄漏
    • 智能指针:尽量使用智能指针防止内存泄漏
    • new分配数组的时候,必须使用delete[ ] 释放内存
#include <iostream>

class MyClass {
public:
    MyClass() {
        std::cout << "Constructor called!" << std::endl;
    }
    ~MyClass() {
        std::cout << "Destructor called!" << std::endl;
    }
};

int main() {
    MyClass* objArray = new MyClass[3]; // 分配 MyClass 类型的对象数组,调用构造函数
    delete[] objArray;                  // 释放内存,调用析构函数
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT基础教程(QEvent事件和事件过滤器)

文章目录 前言一、具体介绍二、具体案例1.鼠标事件2.键盘事件3.窗口事件 三、事件过滤器事件过滤器的工作原理 总结 前言 本篇文章将带大家来学习QT中的QEvent事件&#xff0c;QEvent 是 Qt 框架中的一个核心类&#xff0c;用于处理各种事件。在 Qt 的事件处理系统中&#xff…

framebuffer(帧缓冲)

framebuffer 在Linux系统中&#xff0c;Framebuffer通常是指Framebuffer设备&#xff0c;它是一种特殊的字符设备&#xff0c;在Linux系统中&#xff0c;Framebuffer设备使得程序员可以通过其设定的函数接口直接访问硬件&#xff0c;而不需要通过CPU。 framebuffer的一般操作流…

江协科技51单片机学习- p29 DS18B20温度传感器

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

2-49 基于matlab的表面缺陷的自动分割

基于matlab的表面缺陷的自动分割。基于梯度图操作&#xff0c;对得到的梯度图进行开运算去噪&#xff0c;二值化后经过一定的形态学处理得到缺陷轮廓。通过在两个尺度上同时操作&#xff0c;高尺度的图精细&#xff0c;噪点多&#xff1b;低尺度的图粗糙&#xff0c;但包含的噪…

【人工智能】人工智能概述(二)人工智能的关键技术

文章目录 一. 机器学习与深度学习1. 机器学习2. 深度学习 二. 计算机视觉1. 基本概念和分类2. 未来计算机视觉面临的主要挑战 三. 自然语言处理1. 基本概念与分类2. 自然语言处理面临的四大挑战 四. 知识图谱1. 基本概念2. 应用场景 五. SLAM技术1. 基本概念2. 主要分类 六. 人…

Halcon 感兴趣区域

一 感兴趣区域 机器视觉中感兴趣区域是必不可少的&#xff0c;尤其是Halcon。其目的是将集中处理图像中的特定部分。此方法将区域信息与图像矩阵相结合&#xff0c;只与图像中的某些区域保持关联&#xff0c;减少图像处理的像素。使用ROI的优势&#xff1a;第一&#xff0c;减…

Redis学习[1] ——基本概念和数据类型

Redis学习[1] ——基本概念和数据类型 一、Redis基础概念 1.1 Redis是什么&#xff0c;有什么特点&#xff1f; Redis是一个基于**内存的数据库&#xff0c;因此读写速度非常快**&#xff0c;常用作缓存、消息队列、分布式锁和键值存储数据库。支持多种数据结构&#xff1a;…

网络协议二 : 使用Cisco Packet Traceer工具模拟网络环境,集线器,网桥,交换机,路由器,IP,同一网段

1. 安装 Cisco Packet Tracer baidu 网盘地址&#xff0c;感谢大神分享 安装&#xff0c;破解&#xff0c;中文化&#xff0c;都有说明&#xff0c;建议使用7.x的那个版本&#xff0c;感觉比8.x的翻译要完整一点 https://pan.baidu.com/s/18iWBOfhJJRhqgQqdNQcfMQ?pwddcch#…

【C++】实验七

题目&#xff1a; 1、自己找规律利用数组完成下列数据的输出&#xff1a; 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 思路&#xff1a;数据是斐波那契数列的前20项。该数列特点是除第一第二项以…

公交车客流统计产品介绍

在当今智能科技与交通运输融合的背景下&#xff0c;一款新型公交车客流统计产品应运而生。该系统采用先进的双目客流统计算法&#xff0c;实现多通道视频的客流数据统计&#xff0c;以其高实时性和98%的准确性在复杂环境下准确统计人数。 产品特点 双目客流统计算法 该公交车客…

Vscode报错:line too long (84 > 79 characters)

原因&#xff1a;不允许一行超过79个字母&#xff0c;但是该行代码超出该范围。 参考博客&#xff1a;解决Vs CodeFlake8 报错line too long (108 &#xff1e; 79 characters)Flake8(E501)_flake8 line too long-CSDN博客

Git安装以及配置Gitee秘钥

一、Windows环境GIt安装 1、官网下载git&#xff0c;地址&#xff1a;Git - Downloads 2、安装成功后&#xff0c;点击鼠标右键会有Git GUI Here&#xff08;图形界面&#xff09;和Git Bash Here&#xff08;命令窗口&#xff09; 3、点击Git Bash Here,分别输入以下命令&…

数据库练习4

建库使用库 修改student 表中年龄(sage)字段属性&#xff0c;数据类型由int 改变为smallint 为Course表中Cno 课程号字段设置索引,并查看索引 为SC表建立按学号(sno)和课程号(cno)组合的升序的主键索引&#xff0c;索引名为SC_INDEX 创建一视图 stu info,查询全体学生的姓名&am…

Lingo求解器百度云下载 ling 8.0/lingo 18安装包资源分享

如大家所熟悉的&#xff0c;Lingo是Linear Interaction and General Optimizer的缩写&#xff0c;中文名称为“交互式线性和通用优化求解器”&#xff0c;是一套专门用于求解最优化问题的软件包。 在大部分人认知里&#xff0c;Lingo可用于求解线性规划、二次规划、整数规划、…

【中项】系统集成项目管理工程师-第7章 软硬件系统集成-7.3软件集成

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

交通数据处理-计算途径某些路段的车辆数

根据车辆的运行轨迹&#xff0c;计算先经过某些路段&#xff0c;再经过某些路段的车辆数。 欢迎关注本人公众号--交通数据探索师 如下表&#xff0c; 其中&#xff1a;vehicle: 车辆编号&#xff1b;route: 车辆轨迹。 以第一行为例&#xff0c;车辆car1按顺序经过了路段123…

从0开始搭建vue + flask 旅游景点数据分析系统(三):开发header部分

这一期开始开发header部分&#xff0c;预期实现两个目标&#xff1a; 右侧显示用户名、退出按钮和头像左侧显示系统的访问的路径 1 修改Layout.vue 先修改el-header部分, <el-header class"header"> <!-- <div class"logo">My Ad…

【leetcode 详解】生成特殊数字的最少操作【中等】(C++思路精析)

题目见下&#xff1a; 测试数据: 解题思路笔记&#xff1a; 最初拿到这道题是很蒙的&#xff0c;联想不到什么数据结构的模型&#xff08;肯定是笔者积累太少了&#xff09;&#xff0c;甚至惯性地想怎么实现“删除数字”的操作&#xff1a;在原字符串中抽出一个字符然后将剩…

趋动科技与天数智芯携手构筑全场景高效算力底座

近日&#xff0c;趋动科技与天数智芯正式推出联合解决方案&#xff0c;该方案基于趋动科技OrionX AI算力资源池化软件以及天数智芯通用GPU产品构建AI算力资源池&#xff0c;实现异构算力资源的统一纳管。 经测试&#xff0c;OrionX AI算力资源池化软件与天数智芯通用GPU产品相…

数据结构·红黑树

1. 红黑树的概念 红黑树&#xff0c;是一种搜索二叉树&#xff0c;但在每个节点上增加一个存储位表示节点的颜色&#xff0c;可以是Red或Black。通过对任意一条从根到叶子的路径上各个节点着色方式的限制&#xff0c;红黑树确保没有一条路径会比其他路径长出两倍&#xff0c;因…