当前位置: 首页 > news >正文

C++入门基础

1 命名空间

        命名空间(Namespace)是 C++ 解决标识符命名冲突的核心机制,通过将全局作用域划分为独立区域,实现代码隔离。

1.1 命名空间的定义

  • 核心目的:创建独立作用域,避免名称污染。

1. 基本定义语法

namespace NamespaceName {  // 命名空间名称(通常用项目名/模块名)// 成员列表(可包含任意合法标识符)int variable;          // 变量void function();       // 函数class MyClass { ... }; // 类struct Node { ... };   // 结构体
}

2. 嵌套命名空间

  • 支持多层命名空间,解决复杂模块的命名冲突。
namespace Project {namespace Core {          // 内层命名空间int version = 1;}namespace GUI {           // 同级命名空间void init() { ... }}
}

3. 跨文件合并特性

  • 同一工程中同名命名空间自动合并。
namespace N1
{int rand = 10;
}
namespace N1//同一工程同命名空间自动合并
{int a = 20;
}int main()
{
cout << N1::rand << endl;
cout << N1::a <<endl;
}
  • 在同一工程中,N1中嵌套的命名空间N2,若在N1外再定义一个N2,次是N2不能与N1中的N2合并。
namespace N1
{namespace N2{int Sub(int x, int y){return x - y;}}}namespace N2//在N1外定义N2
{int Mult(int x, int y){return x * y;}
}int main()
{//cout << N1::N2::Mult(4, 3) << endl;//报错,这里不能合并
}

1.2 命名空间的使用

1. 作用域限定符 ::(精确访问)

  • 语法: Namespace::member
  • 场景:精准调用特定成员,避免歧义
namespace N1
{int a = 20;
}int main()
{cout << N1::a << endl;//精确访问,'name::member'
}

2. using声明(引入单个成员)

  • 语法:using Namespace::member;
  • 场景:频繁使用某空间的特定成员
namespace N1
{int rand = 10;//定义变量int Add(int x, int y)//定义函数{return x + y;}
}using N1::Add;//'using namespace::member'
int main()
{cout << Add(1, 2) << endl;
}

3. using namespace(引入整个空间)

  • 语法:using namespace Namespace;
  • 场景:快速原型开发(生产代码慎用
namespace N1
{int rand = 10;//定义变量int Add(int x, int y)//定义函数{return x + y;}
}using namespace N1;
int main()
{cout << Add(1,2) << endl;
}
  •  若在N1中定义N2,在N1外再定义一个N2,当引入N1时,会发生冲突。
namespace N1
{int rand = 10;//定义变量int Add(int x, int y)//定义函数{return x + y;}struct Node//定义类{struct Node* next;int val;};namespace N2//可以嵌套命名空间{int Sub(int x, int y){return x - y;}}}namespace N2
{int Mult(int x, int y){return x * y;}
}
using namespace N1;int main()
{cout << N2::Mult(4, 3) << endl;//报错,N2不明确
}

1.3 典型错误规避

  • 错误1:头文件使用using namespace
// mylib.h(污染包含此头文件的所有源文件)
using namespace std; // 绝对禁止!
  • 错误2:忽略嵌套空间的作用域
namespace A {int x;namespace B {int x; // 合法但易混淆}
}
A::x = 1;      // 访问外层 x
A::B::x = 2;   // 必须完整指定

1.4 与 C 语言的对比优势

场景

C 语言方案

C++ 命名空间方案

库函数冲突

需重命名函数 lib1_init()

Lib1::init() 自然隔离

大型项目模块化

前缀约定 modA_var(易出错)

ModA::var 结构化分组

第三方库集成

可能需修改源码

通过命名空间无缝共存

1.5 命名空间的核心价值

  • 隔离性:划分逻辑模块,避免全局名称冲突
  • 封装性:隐藏实现细节(结合匿名命名空间)
  • 扩展性:支持嵌套和合并,适应工程增长

 黄金准则

  • 头文件禁止 using namespace
  • 生产代码优先使用 作用域限定符using声明
  • 嵌套命名空间不超过两层(Project::Module::func)

2 C++输入输出流(I/O Stream)

        C++通过流(Stream)机制实现数据输入输出,核心组件包含 <iostream> 头文件中的 cout、cin 及运算符 <<、>>。

2.1 核心组件与基础用法

组件

类型

作用

基础用法示例

cout

ostream 对象

标准输出(控制台)

cout << "Hello";

cin

istream 对象

标准输入(键盘)

cin >> age;

<<

插入运算符

将数据插入输出流

cout << x << endl;

>>**

提取运算符

从输入流提取数据到变量

cin >> name >> id;

endl

操纵符

插入换行并刷新缓冲区

cout << "Done" << endl;

\n

转义字符

插入换行(不刷新缓冲区

cout << "Line1\nLine2";

#include <iostream>
using std::cout; // 推荐方式:只引入必要组件
using std::cin;
using std::endl;int main() {int age;std::string name;// 输入示例cout << "Enter name and age: ";cin >> name >> age;   // 从键盘提取数据// 输出示例cout << name << " is " << age << " years old." << endl;
}

2.2 关键特性解析

1. 自动类型识别

  • 无需格式说明符(如C的%d),自动推导数据类型。
int x = 10;
double y = 3.14;
char c = 'A';cout << x << " " << y << " " << c; // 输出: 10 3.14 A

2. 链式调用

  • 通过运算符重载支持连续操作。
// 连续输出
cout << "Sum: " << (a + b) << ", Product: " << (a * b) << endl;// 连续输入
cin >> width >> height >> depth;

2.3 常用格式控制(需 <iomanip> 头文件)

操纵符

作用

示例

std::setw(n)

设置字段宽度为 n

cout << setw(10) << x;

std::setprecision(n)

设置浮点数精度为 n 位

cout << fixed << setprecision(2) << 3.14159; // 3.14

std::fixed

固定小数格式

搭配 setprecision 使用

std::left

左对齐输出

cout << left << setw(10) << "Hi";

std::right

右对齐(默认)

cout << right << setw(10) << 42;

std::hex

十六进制输出

cout << hex << 255; // ff

 示例:格式化表格输出

#include <iomanip>cout << left << setw(15) << "Name" << setw(10) << "Age" << endl;
cout << setw(15) << "Alice" << setw(10) << 25 << endl;
cout << setw(15) << "Bob" << setw(10) << 30 << endl;输出:
Name            Age       
Alice           25        
Bob             30        

2.4 对比C语言的优化

特性C (printf/scanf)C++ (cout/cin)
类型安全✘ 需手动匹配格式符✔ 自动类型推导
可扩展性✘ 不支持自定义类型✔ 可重载 <</>> 运算符
代码简洁性✘ 格式字符串与变量分离✔ 链式调用,直接拼接数据
错误处理✘ 无内置校验机制✔ 流状态标志(failbit等)
国际化支持✘ 弱✔ 宽字符支持(wcout/wcin

3 缺省参数

        缺省参数是 C++ 中提升函数灵活性的重要特性,允许在函数声明时指定参数默认值

3.1 核心概念

1. 定义:在函数声明中为参数赋予默认值,调用时若省略该实参,则自动使用默认值。

2. 本质作用

  • 向后兼容:新增参数时不影响旧代码
  • 简化调用:减少冗余参数传递
  • 增强可读性:明确常用配置值

3.2 参数分类与使用

1. 全缺省参数

  • 定义:所有参数均有默认值
  • 调用自由:可传 0~N 个参数
void connect(string ip="127.0.0.1", int port=8080, string user="admin");// 合法调用
connect();                     // ip="127.0.0.1", port=8080, user="admin"
connect("192.168.1.100");      // ip="192.168.1.100", port=8080, user="admin"
connect("192.168.1.100", 9090); // ip="192.168.1.100", port=9090, user="admin"

2. 半缺省参数

  • 定义:部分参数有默认值
  • 关键约束:默认值必须从右向左连续给出,调用时实参按从左向右顺序匹配。
// 正确:默认值从右向左连续
void log(string msg, int level=1, bool timestamp=true); // 错误:默认值不连续
void errFunc(int a=10, int b, int c=30); // 编译报错!// 合法调用
log("Start");               // msg="Start", level=1, timestamp=true
log("Error", 3);            // msg="Error", level=3, timestamp=true
log("Debug", 2, false);     // msg="Debug", level=2, timestamp=false

3. 底层原理剖析

  • 编译期替换机制:编译器在调用点自动补全缺失参数。
// 源代码
log("Message");// 编译后实际执行
log("Message", 1, true);  // 自动补全默认值

3.3 关键约束与陷阱

声明与定义分离规则

  • 默认值仅能出现在声明中(通常位于头文件)
  • 定义中禁止重复指定(源文件仅写参数名)
// mylib.h(声明)
void draw(int x, int y, int color=0); // mylib.cpp(定义)
void draw(int x, int y, int color) { // 此处不可写 color=0/* 实现 */
}

3.4 工程实践指南

适用场景

场景

示例

优势

扩展函数功能

void save(string path="")

旧代码兼容新功能

简化高频调用

void setColor(Color c=RED)

减少重复参数

配置复杂对象

openFile(bool async=true)

明确常用配置

4 函数重载

        函数重载是 C++ 的核心特性,允许在同一作用域内定义多个同名函数,通过参数列表区分不同实现。

4.1 核心概念与分类

1. 定义

        在同一作用域中声明多个同名函数,通过参数列表的差异(类型/数量/顺序)实现不同功能。

2. 重载依据

分类合法重载示例非法示例
参数类型不同int add(int, int) vs double add(double, double)
参数数量不同void log() vs void log(string msg)
参数顺序不同void set(int, char) vs void set(char, int)
返回值不同-int f() vs void f() ✘
缺省参数差异-void g(int) vs void g(int=0) ✘

示例

void print(int val) 
{ cout << "Integer: " << val; 
}
void print(double val) 
{ cout << "Double: " << val; 
}
void print(string val) 
{cout << "String: " << val; 
}print(10);     // 调用 print(int)
print(3.14);   // 调用 print(double)
print("text"); // 调用 print(string)

4.2 重载与缺省参数的交互

1. 危险组合:重载 + 缺省参数

void process(int a) 
{cout << "process(int a)" << endl;
}      // 重载1
void process(int a, int b = 0)
{cout << "process(int a, int b = 0)" << endl;} int main()
{process(10); // 歧义!可能调用:// 重载1: process(10)// 重载2: process(10, 0) → 冲突!
}

2. 解决方案

  • 方案1:避免同时使用重载和缺省参数
  • 方案2:明确区分参数数量

5 引用

引用是 C++ 的核心特性,本质是变量的别名,与指针功能相似但更安全简洁。

5.1 引用的概念

1. 本质定义

引用是为已存在变量创建的别名,不分配独立内存,与原始变量共享地址空间。

2. 语法形式

类型& 引用名 = 原变量;  // 必须初始化
int num = 10;
int& ref = num;      // ref是num的别名

3. 底层实现

编译器将引用处理为自动解引用的指针:

; int& ref = num;
lea eax, [num]       ; 取num地址 -> 相当于指针
mov dword ptr [ref], eax; ref = 20;
mov eax, dword ptr [ref]  ; 获取地址
mov dword ptr [eax], 14h  ; 解引用赋值 -> *ptr=20

5.2 引用的三大特性

特性说明示例违反后果
定义时必须初始化不存在空引用int& r = x;编译错误
一个变量多个引用支持多别名int& r1=x; int& r2=x;-
不可重绑定初始化后不能更改指向r = y; // 错误!实际是赋值操作
void TestRef()
{int a = 10;//int& ra;//引用在定义时必须初始化,✘ 错误:未初始化int& ra = a;// √ 正确初始化int& rra = a;//一引用多个实体,√ a的第二个别名int b = 20;ra = b;//✘ 非重绑定!实际将b的值赋给a(a=20)//int& ra = b;//✘引用一旦引用一个实体,不能引用其他实体了int& rrra = ra;//引用也可有别名}

 5.3 常引用(const Reference)

1. 作用:避免意外修改数据,增强安全性。

2. 使用规则

场景语法示例
绑定普通变量const T& ref = var;const int& cr = num;
绑定字面量const T& ref = value;const int& cr = 42;
类型转换绑定const T& ref = expr;const int& cr = 3.14; // int(3)
void TestConstRef()
{const int a = 10;//int& ra = a;//a为不可更改的常量,int& ra中,ra是可变的量,a的权限放大,编译时出错const int& ra = a;//int& b = 10;//10为常量,引用后10变为可更改的量,权限放大,编译出错const int& b = 10;double d = 3.14;//int& rd = d;//double转换为int会发生强制类型转换,产生临时变量,再将临时变量赋值给rd,由于临时变量具有常性,也属于权限放大const int& rd = d;
}

 5.4 引用使用场景

1. 作函数参数(避免拷贝)

  • 场景:传递大对象(结构体/类)
  • 优势:零拷贝开销,直接操作原对象
void Swap(int& left, int& right)
{int tmp = left;left = right;right = tmp;cout << left << " " << right << endl;
}int main()
{int a = 1;int b = 2;Swap(a, b);
}

2. 作函数返回值(需谨慎)

  • 安全场景:返回静态变量/全局变量
int& Addd(int a, int b)
{static int c = a + b;return c;// 安全:静态变量生命周期持续
}
  • 危险场景:返回局部变量(悬空引用)
int& Addd(int a, int b)
{int c = a + b;return c;// 错误!局部变量销毁后引用无效
}
int main()
{int& ret = Add(1,2);cout << ret << endl;//c为Addd的局部函数,出函数后销毁,ret接受的是随机值
}

5.5 传值 vs 传引用效率对比

1. 测试代码

struct BigData
{ int arr[10000]; 
};// 传值(深拷贝)
void byValue(BigData data) 
{}// 传引用(零拷贝)
void byRef(BigData& data)
{}// 测试函数
void test() 
{BigData data;// 测试传值clock_t t1 = clock();for (int i = 0; i < 100000; ++i) byValue(data);cout << "ByValue: " << clock() - t1 << "ms\n";// 测试传引用t1 = clock();for (int i = 0; i < 100000; ++i) byRef(data);cout << "ByRef: " << clock() - t1 << "ms\n";
}
int main()
{test();
}
  • 测试结果:大对象传引用性能碾压传值,小对象(int等)差异可忽略

5.6 引用 vs 指针全面对比

特性引用(Reference)指针(Pointer)
本质别名(语法层)内存地址(硬件层)
内存占用无独立内存(符号表记录)占用4/8字节存储地址
初始化必须初始化可滞后初始化(危险!)
重绑定禁止(终身绑定)允许任意次数重指向
空值无空引用支持 nullptr
访问方式隐式解引用(直接操作)显式解引用(*ptr
多级间接访问不支持(int&& 是右值引用)支持多级(int** pp
类型安全强类型检查弱类型(void*可任意转换)
sizeof 行为返回原类型大小(sizeof(ref)==sizeof(int)返回指针大小(4/8字节)
自增操作ref++ 即原变量+1ptr++ 指向下一元素
代码可读性更简洁(类似直接变量)需频繁使用 * 和 &

典型代码对比:

// 引用版本(简洁)
void swap(int& a, int& b) {int tmp = a;a = b;b = tmp;
}// 指针版本(繁琐)
void swap(int* a, int* b) {int tmp = *a;*a = *b;*b = tmp;
}// 调用对比
int x=1, y=2;
swap(x, y);     // 引用:自然如普通变量
swap(&x, &y);   // 指针:需取地址操作

5.7 引用核心价值

  • 安全性:无空引用、必须初始化、不可重绑定
  • 高效性:传参/返回避免拷贝(尤其大对象)
  • 简洁性:无需解引用,代码更直观
  • 语义明确:别名语义 vs 指针的地址语义

6 内联函数

内联函数是 C++ 中提升性能的关键特性,通过消除函数调用开销优化小型高频函数。

6.1 内联函数的概念

1. 核心定义

  • inline关键字修饰的函数,编译器会尝试在调用点直接展开函数体,避免函数调用的栈帧开销。

2. 基础语法

// 声明 + 定义(通常直接在头文件)
inline int add(int a, int b) 
{return a + b;
}

6.2 内联函数的五大特性

特性说明示例/注意事项
编译期展开函数体被插入调用处(非函数调用)类似宏替换,但有类型检查
空间换时间可能增大二进制文件体积适用于小函数(建议 ≤ 10行)
编译器建议性inline 只是提示,编译器可拒绝展开递归/复杂函数会被忽略(g++ -Winline 可警告)
头文件定义规则必须在每个使用它的文件中可见(通常直接定义在头文件)违反导致链接错误(undefined reference
调试支持Debug 模式默认关闭展开(需手动开启),Release 模式自动优化VS 设置:项目属性 → C/C++ → 优化 → 内联函数扩展 → 只适用于 __inline (/Ob1)

 6.3 内联函数 vs 宏函数

对比项内联函数宏函数 (#define)
处理阶段编译期预编译期
类型安全✔ 编译器检查类型✘ 纯文本替换
调试✔ 可调试展开后代码✘ 调试时显示未替换的宏名
副作用无(参数只计算一次)可能多次计算参数(#define SQUARE(x) x*x → SQUARE(a++) 错误)
作用域遵守命名空间/类作用域全局替换
复杂功能支持循环/递归等完整语法仅支持简单表达式
  •  宏函数陷阱示例
#define MAX(a,b) ((a) > (b) ? (a) : (b))int x = 1, y = 2;
int z = MAX(x++, y++); // 展开后:((x++) > (y++) ? (x++) : (y++))
// 结果:x=2, y=4, z=3 (非预期行为!)
  • 内联函数安全实现
inline int max(int a, int b) 
{return a > b ? a : b;
}
// 调用:max(x++, y++) → 参数先计算一次,安全

6.4 内联函数最佳实践

1. 适用场景

场景示例性能收益
高频小函数Getter/Setter消除调用开销
数学运算向量点积、矩阵乘法避免栈操作成本
模板辅助函数模板中的工具函数头文件必须内联

 2. 禁用场景 

  • 大函数(> 20行):显著增大代码体积
  • 递归函数:编译器通常拒绝内联(除尾递归优化)

6.5 内联函数底层机制

1. 汇编代码对比

// 普通函数调用
int c = add(a, b);
// 汇编:
push   b       ; 参数入栈
push   a
call   _add    ; 调用函数(开销大)
add    esp, 8  ; 清理栈
mov    [c], eax// 内联函数展开
int c = a + b;  // 直接展开
// 汇编:
mov  eax, [a]
add  eax, [b]
mov  [c], eax

6.6内联函数核心价值

  • 性能优化:消除函数调用开销(栈帧分配/参数传递/返回跳转)
  • 安全替代宏:类型安全 + 可调试 + 无副作用
  • 零开销抽象:封装小操作不牺牲性能

 黄金准则

  1. 内联函数 ≤ 10 行代码
  2. 在头文件中定义实现
  3. 通过性能测试验证效果
  4. 优先用 constexpr 替代编译期计算需求

auto关键字深度解析

auto 是 C++11 引入的类型推导关键字,用于自动推断变量类型,提升代码简洁性与可维护性。

7.1 类型别名思考

1. 长类型名问题

复杂类型(如迭代器、闭包)使代码冗长且易错:

std::map<std::string, std::vector<int>>::iterator it = data.begin(); // 冗长

2. typedef 的局限性

  • 无法处理模板场景
  • 可能引入意外行为:
typedef char* pstring;
const pstring p1 = 0;  // 实际类型:char* const(常量指针)
const char* p2 = 0;    // 指向常量的指针 → 两者不同!

3. auto 的解决方案

auto it = data.begin();  // 自动推导迭代器类型

7.2 auto 简介

1. 核心定义:auto 指示编译器根据初始化表达式自动推导变量类型。

2. 基础用法

auto a = 10;        // int
auto b = 3.14;      // double
auto c = "hello";   // const char*
auto d = getValue(); // 推导为getValue()返回类型

3. 与 decltype 对比

特性autodecltype
推导依据初始化表达式的值类型表达式的声明类型(不计算)
典型场景变量声明复杂表达式类型获取
示例auto x = 42; → intdecltype(f()) y = x; → f()返回类型

7.3 auto 使用细则

1. 与指针和引用结合

语法推导规则示例
auto忽略引用,推导值类型int x=1; int& rx=x; auto a=rx; → aint
auto*推导为指针类型auto* p = &x; → int*
auto&推导为引用类型auto& r = x; → int&
const auto保留顶层constconst int y=2; auto z=y; → int(const丢失)
const auto&保留底层const和引用const auto& cr = y; → const int&

  关键测试

int x = 10;
const int cx = x;
auto a = cx;          // a 是 int(const被丢弃)
const auto b = x;     // b 是 const int
const auto& c = cx;   // c 是 const int&

2. 多变量声明规则:同一语句中所有变量必须推导为相同类型。

auto a = 10, *b = &a;    // √ a是int, b是int*
auto c = 20, d = 3.14;   // ✘ 错误:c为int, d为double

3. 结构化绑定:auto用于解构复合类型。

std::tuple<int, string> getData() { return {42, "Alice"}; }auto [id, name] = getData(); // id=int, name=string

7.4 auto 不能推导的场景

1. 函数参数

void foo(auto param) { ... } // ✘ 错误,不能作为函数参数

2. 类非静态成员变量

class MyClass {auto value = 10; // ✘ 错误
};

3. 数组类型

auto arr[] = {1, 2, 3}; // ✘ 错误,不能直接用来声明数组
int arr2[] = {1, 2, 3}; // √ 正确

4. 未初始化变量

auto x; // ✘ 错误:缺少初始化表达式

7.5 auto 核心价值

  • 代码简洁性:减少冗余类型声明(尤其模板和迭代器)
  • 泛型编程支持:配合模板/Lambda 实现通用代码
  • 可维护性:类型变更时自动适应(如函数返回类型修改)

 黄金准则

  • 优先在局部变量使用 auto
  • 避免在接口头文件中使用
  • 复杂表达式配合 decltype 确保正确性

8 范围for循环的语法

作用:简化遍历有范围集合(如数组、容器)的过程,避免手动控制循环边界。

语法格式

for (declaration : range_expression) {// 循环体
}

declaration:声明一个变量,用于迭代访问范围内的每个元素。

  • 常用auto自动推导元素类型(如 auto e)。
  • 需修改元素时用引用(如 auto& e);只读访问可用值拷贝(如 int e)。

range_expression:被迭代的范围(如数组、标准库容器)。

示例

int array[] = {1, 2, 3, 4, 5};
// 修改元素(使用引用)
for (auto& e : array) {e *= 2; // 每个元素变为2倍
}
// 只读访问(使用值拷贝)
for (auto e : array) {cout << e << " "; // 输出:2 4 6 8 10
}

8.1 范围for的使用条件

范围必须明确

  • 编译器需能在编译时确定迭代的起止边界。
  • 数组:范围是 [首元素, 末尾元素](通过数组大小隐式确定)。
  • 类类型:需提供 begin() 和 end() 成员函数,返回指向范围起止的迭代器。

常见错误:函数参数中的数组实际是指针,范围不确定:

void TestFor(int array[]) {  // array 退化为指针for (auto& e : array)   // 错误!范围未知cout << e << endl;
}

注意事项

  • 循环控制:可用 continue 跳过当前迭代,或用 break 终止整个循环(与传统 for 行为一致)。
  • 类型推导:推荐用 auto 避免类型书写错误,尤其复杂容器(如 std::map<std::string, int>)。

8.2 总结

关键点

说明

语法

for (auto x : range) → 只读; for (auto& x : range) → 可修改元素

范围确定性

数组需完整传入;类需提供 begin()/end()

迭代器要求

对象必须支持 ++ 和不等比较(!=

适用场景

遍历数组、标准库容器(vector/array/list 等)

  重要:函数参数中的数组无法使用范围for(因退化为指针,范围未知)。

9 指针空值 nullptr

9.1 指针空值的问题

  • 传统方式:使用 NULL 或 0 初始化空指针。
int* p1 = NULL;
int* p2 = 0;
  • NULL 的本质:在标准库头文件(如 <stddef.h>)中定义为。
#ifdef __cplusplus
#define NULL 0      // C++中定义为整型0
#else
#define NULL ((void*)0)  // C中定义为无类型指针
#endif
  • 核心问题NULL 在 C++ 中被视为整型常量 0,导致重载函数歧义。
  • 原因:编译器将 NULL 解析为整型 0,而非指针类型。
void f(int) { cout << "f(int)" << endl; }
void f(int*) { cout << "f(int*)" << endl; }int main() {f(0);        // 调用 f(int)(符合预期)f(NULL);     // 调用 f(int)!但预期是 f(int*)f((int*)NULL); // 必须强制转换才能调用 f(int*)
}

9.2 C++11 的解决方案:nullptr

  • 引入目的:明确区分空指针与整型 0
  • 类型安全nullptr 是指针空值常量,类型为 std::nullptr_t(隐式转换为任意指针类型)。
  • 消除歧义
f(nullptr);  // 明确调用 f(int*)
  • 无需头文件nullptr 是 C++11 关键字,直接使用。
  • 大小与指针相同
sizeof(nullptr) == sizeof(void*);  // 32位系统为4字节,64位为8字节

9.3 使用规范

  • 初始化指针
int* p = nullptr;  // 正确:明确空指针
char* q = nullptr; // 任意指针类型均可
  • 禁止隐式转换
int a = nullptr;   // 错误!不能将 nullptr 赋值给整型
  • 模板与类型推导
auto ptr = nullptr; // ptr 类型是 std::nullptr_t

9.4 代码建议

场景推荐方式不推荐方式
初始化指针int* p = nullptr;int* p = NULL;
函数重载中表示空指针f(nullptr);f(0); 或 f(NULL);
条件判断if (p != nullptr)if (p != NULL)

 9.5 总结

关键点说明
解决历史问题消除 NULL 导致的类型歧义(整型 vs 指针)。
类型安全明确表示指针空值,不与整型 0 混淆。
兼容性C++11 及以上支持,现代编译器默认启用。
工程实践新项目强制使用 nullptr;旧项目迁移时逐步替换 NULL/0
  • 最佳实践始终使用 nullptr 表示空指针,避免 NULL 和 0,以提高代码可读性和类型安全性。 
http://www.lqws.cn/news/135937.html

相关文章:

  • JavaScript基础:运算符
  • 本地IP配置
  • 【电赛培训课程】电子设计竞赛工程基础知识
  • psycopg2-binary、pgvector、 SQLAlchemy、 PostgreSQL四者的关系
  • typescript中的type如何使用
  • FSC认证概述?FSC认证的核心原则与标准?FSC认证的市场价值与意义
  • QRSuperResolutionNet:一种结构感知与识别增强的二维码图像超分辨率网络(附代码解析)
  • SSH登陆Linux常见问题大全
  • RAMSUN分享全新超值型MM32F0050系列MCU
  • 航芯MCU使用IAR+Jlink调试
  • 关于单片机的基础知识(一)
  • yFiles:专业级图可视化终极解决方案
  • Maskrcnn网络结构学习
  • DataStreamAPI实践原理——快速上手(实操详细版)
  • AbMole|Temozolomide在胶质母细胞瘤研究中为什么会常用到?
  • 300道GaussDB(WMS)题目及答案。
  • 2506,wtl的通知事件
  • LangChain开发环境搭建
  • 【Linux系统】命令行参数 和 环境变量(含内建命令介绍)
  • 行为型-迭代器模式
  • 主流Agent开发平台学习笔记:扣子罗盘coze loop 功能拆解
  • 68 VG的基本信息查询
  • Visual Studio如何引入第三方头文件——以部署OpenGL为例
  • 综合案例:斗地主
  • 【算法训练营Day06】哈希表part2
  • 基于单片机的FFT的频谱分析仪设计
  • css实现圆环展示百分比,根据值动态展示所占比例
  • Haystack:AI与IoT领域的全能开源框架
  • 【conda配置深度学习环境】
  • PhpStorm设置中文