1.#include使用
在C/C++中,#include
预处理指令用于包含头文件,这些头文件通常包含了函数声明、宏定义以及其他的声明和定义。#include
指令后面跟着的文件名可以使用双引号 ""
或尖括号 <>
来指定,它们之间有一些区别。
- 双引号
""
:- 当文件名被双引号
""
括起来时,预处理器会首先在当前源文件所在目录下查找要包含的文件。 - 如果在当前目录下找不到指定的文件,预处理器会继续在系统默认的头文件目录中查找(通常是编译器的包含目录)。
- 当文件名被双引号
- 尖括号
<>
:- 当文件名被尖括号
<>
括起来时,预处理器会直接在系统默认的头文件目录中查找要包含的文件。 - 它通常用于包含系统提供的标准库头文件或者其他全局可用的头文件。
- 当文件名被尖括号
2. 常量指针和指针常量的区别
2.1 const的优点
在C/C++中,宏定义使用 #define
来定义一个符号常量或者带参数的代码替换。宏定义在预处理阶段被简单地进行文本替换,它不会进行任何类型检查。这意味着在宏定义中,不会进行任何类型检查,而且宏定义的参数也不会进行类型检查。
2.2 常量指针和指针常量的区别
const修饰的变量不能作为左值,初始化完不能被修改。
const的编译方式不同,在c中const就是当作变量来编译生成指令的,c++中,所有出现const常量名字的地方,都被常量的初始化替换。
在c语言中,const修饰的量可以不用初始化(但是没啥意义) ,但也不是常量,叫做常变量
在c++中,,const修饰的量必须初始化,叫做常量
C++/C中const的区别 - 不同初始化方式对C++中const量性质的影响_c const没有初始化-CSDN博客
3. c++11的新特性
3.1 初始化列表
- 初始化列表允许使用
{}
语法来初始化数组、容器和类对象。 - 它提供了一种更简洁、一致的初始化方式,并且可以防止窄化转换。
3.2 auto关键字
3.3 decltype关键字
3.4 范围for循环
3.5 nullptr关键字
void fun(int x) {cout << x << endl;
}void fun(int* p) {if (p != nullptr)cout << *p << endl;
}int main() {fun(0); // 在 C++98 中编译可能失败,存在二义性,但在 C++11 中编译为 fun(int)int* p = nullptr; // 使用 nullptr 初始化空指针return 0;
}
3.6 lambda表达式
Lambda表达式是一种匿名函数,它允许我们在需要函数作为参数的地方以内联的方式定义函数。
3.7 智能指针
3.8 右值引用
右值引用是C++11引入的特性,用于标识对临时对象(右值)的引用。它们通过 &&
符号来声明,与左值引用 &
相对应。
右值引用的主要目的是提高C++中的移动语义(Move Semantics),允许在不进行资源拷贝的情况下将临时对象的内容转移给另一个对象,从而提高性能和效率。
右值引用通常与移动构造函数和移动赋值运算符一起使用,这些特殊的成员函数允许在对象之间转移资源而不是复制资源。这对于管理动态分配的内存和其他资源非常有用,因为它减少了不必要的内存分配和释放。
3.9 移动语义 以及 移动构造函数和移动赋值运算符
移动语义是C++11引入的特性,它允许在不进行资源复制的情况下将资源从一个对象转移到另一个对象。这样做可以避免不必要的内存分配和释放,提高程序的性能和效率。移动语义通常与右值引用一起使用,用于转移临时对象的资源。
移动构造函数和移动赋值运算符是类的特殊成员函数,它们用于实现移动语义。移动构造函数允许将资源从一个对象移动到另一个对象,而不是进行深度复制。移动赋值运算符执行类似的操作,允许在赋值操作中转移资源。这两个特殊成员函数通常使用右值引用参数来实现。
#include <iostream>
#include <vector>class MyVector {
public:int size;int* data;// 构造函数MyVector(int s) : size(s), data(new int[s]) {std::cout << "Constructing MyVector of size " << size << std::endl;}// 移动构造函数MyVector(MyVector&& other) noexcept : size(other.size), data(other.data) {other.size = 0;other.data = nullptr;std::cout << "Moving resources from one MyVector to another" << std::endl;}// 析构函数~MyVector() {delete[] data;std::cout << "Destroying MyVector" << std::endl;}
};int main() {// 创建一个临时的MyVector对象MyVector temp(5);// 创建一个新的MyVector对象,并使用移动构造函数将资源从temp移动到vecMyVector vec(std::move(temp));// 这时temp的资源已经被移动到vec,temp不再拥有资源,其析构函数会被调用std::cout << "Size of temp: " << temp.size << std::endl; // 应该输出0// vec现在拥有temp之前的资源std::cout << "Size of vec: " << vec.size << std::endl; // 应该输出5return 0;
}