Modern C++(一)基本概念

1、基本概念

1.1、注释

注释在翻译阶段3会被替换为单个空白字符从程序中移除

1.2、名字与标识符

标识符是一个由数字、下划线、大小写字符组成的任意长度序列。有效的标识符首个字符必须是以A-Z、a-z、下划线开头,。有效的标识符其他字符可以是0-9、A-Z、a-z、下划线。

标识符可以用来命名对象、引用、函数、枚举项、类型、类成员、命名空间、模板、模板特化、形参包(C++11 起)、goto 标号,以及其他实体。

1.3、类型

C++类型系统由以下类型组成:

  • 基础类型
    • void
    • std::nullptr_t
    • 算数类型
      • bool
      • 字符类型:char、signed char、unsigned char、char16_t、char32_t、wchar_t
      • 有符号整数类型:signed char、short int、int、long int、long long int
      • 无符号整数类型:
      • 浮点数类型:float、double、long double
  • 复合类型
    • 引用类型:
      • 左值引用类型
      • 右值引用类型
      • 指针类型
      • 指向成员的指针(成员指针)类型
      • 数组类型
      • 函数类型
      • 枚举类型(有/无作用域)
      • 类类型(非联合/联合体类型)

标量类型:标量类型变量一次仅存储一个值。算术类型、枚举类型、指针类型、成员指针类型、std::nullptr_t都是标量类型

1.3.1、隐式生存期类型

隐式生存期类型是C++20引入的概念,无需显式调用构造函数或使用new表达式,对象的生存期(lifetime)可以隐式开始。

普通生存期类型:

class Person {
public:Person(const std::string& name) : name_(name) {std::cout << "构造: " << name_.c_str() << std::endl;}~Person() {std::cout << "析构: " << name_.c_str() << std::endl;}std::string name_;
};int main()
{void *mem = malloc(sizeof(Person));// 未定义行为!必须先构造再使用// static_cast<Person*>(mem)->name_ = "Alice";Person* p = new (mem) Person("Alice");  // 调用构造函数p->~Person();  // 显式调用析构函数std::free(mem);  // 释放内存
}

隐式生存期类型:

struct Point {int x;int y;
};int main()
{void* memory = std::malloc(sizeof(Point));  // 分配内存// 可以直接使用,无需构造!Point* p = static_cast<Point*>(memory);p->x = 10;  // 合法:内存已被视为Point对象p->y = 20;free(memory); // 释放内存(自动析构,无需显式调用析构函数)
}

隐式生存期类型允许:直接操作未构造的内存,无需显式销毁对象,可直接覆盖内存。优点是预先分配大块内存(内存池),按需创建对象。避免频繁调用构造 / 析构函数,提升内存操作效率。

隐式生存期类型:

  • 标量类型
  • 结构体 / 类需满足:无用户定义的构造函数、析构函数。所有成员和基类都是隐式生存期类型。

1.3.2、静态类型

静态类型(Static Typing)是一种编程语言特性,它要求在编译时明确每个变量、表达式和函数的类型。

1.3.3、动态类型

动态类型(Dynamic Typing)是一个相对概念,主要指程序在运行时确定对象的实际类型,而非编译时。C++ 作为静态类型语言,其核心类型系统是静态的(编译时确定类型),有以下几个机制提供了有限的动态类型特性:

  • 多态:基类指针指向派生类对象
  • RTTI(运行时类型信息)

1.4、对象

1.4.1、对齐

每个对象类型都具有被称为对齐要求的性质,它是一个非负整数(类型是 std::size_t,总是 2 的幂),可以使用alignof和std::alignment_of查询类型的对齐要求,也可以使用alignas要求对齐数。

class Person {
public:Person(const std::string& name) : name_(name) {}
private:std::string name_;
};int main()
{cout << alignof(Person) << endl;cout << std::alignment_of<Person>::value << endl;
}

1.4.2、声明点

声明点(Point of Declaration)是一个编译期概念,它指定了标识符(如变量、函数、类等)在代码中正式生效的位置。

  • 对于变量和函数参数:声明点位于标识符名称之后,初始化表达式(如果有)之前
#include <iostream>int main(int argc, char **argv) {int x = 1;const int y = 2;{int x = x;      // 内部x的作用域在初始化器之前就开始了,所以内部x不能被外部x的值初始化std::cout << "x = " << x << std::endl;int y[y] = {};    // 内部y的作用域在y[y]之后,所以内部的y是一个包含2个int的数组}return 0;
}
  • 类和类模板,枚举的声明点位于该标识符之后:
struct S : public A{ // S 的作用域从冒号开始}enum E : int // E 的作用域从冒号开始,因此内部可以使用枚举类型E
{A = sizeof(E)
};
  • 类型别名或别名模板声明的声明点紧随该别名代表的类型标识之后
using T = int; // 外部 T 的作用域从分号开始
{using T = T*; // 内部 T 的作用域从分号开始,// 但分号前还在外部 T 的作用域中,// 因此等同于 T = int*
}
  • 对于函数:声明点位于函数名称之后,形参列表之前
void func(int x) {  // func的声明点在此处// 函数体中可使用func(如递归调用)
}

1.4.3、生存期

对象的生存期(Lifetime) 是指对象从创建(存储被分配且初始化完成)到销毁(存储被释放或重用)的时间段。理解对象生存期对于避免内存泄漏、悬空指针和资源管理至关重要。

生存期:当对象获取存储并初始化完成后生存期开始。对象的生存期在以下几个时刻结束:

  • 非类类型:销毁该对象时
  • 类类型:析构函数调用开始时
  • 对象占据的存储被释放,或者被其他对象重用
#include <iostream>class A {
public:A() {a = 10;}~A(){}void print() {std::cout << "A: a = "<< a << std::endl;}int a;
};class B {
public:int c;B() {c = 1;}
};void func() {A a;a.~A();new (&a) B;a.print();
}int main(int argc, char **argv) {func();std::cout << "test" << std::endl;return 0;
}

在上述代码func函数里,我们手动调用了a的析构函数,对象a的生命周期结束了,该对象占用的存储还在,但它已经不再是一个有效的对象,后续的print调用实际上时一个未定义的行为。

栈上的内存回收是由操作系统自动完成的,当对象的生命周期结束时,操作系统并不会立即将该对象所占用的内存标记为可用,而是等到整个栈帧(通常对应一个函数调用)结束时才会回收栈上的内存。因此,在对象的生命周期结束后,其所在的内存仍然存在,只是该内存已经不再属于一个有效的对象。

所以析构函数调用后,我们还可以重用a的内存。

生存期分类:

  • 自动生存期:局部变量(非static),从定义处开始,到离开作用域时结束。
  • 静态生存期:全局变量、static局部变量、static成员,从程序启动开始,到程序结束结束。
  • 动态生存期:通过new/new[]分配的对象,从new成功开始,到delete/delete[]结束。
  • 线程局部生存期:thread_local变量,与线程绑定(线程启动时开始,线程结束时结束)。

访问生存期外的对象 或者 重用存储前未结束生存期会导致未定义行为(UB)。

int* p = new int(10);
delete p;
*p = 20; // UB:p指向的对象已销毁struct S { ~S() {} };
S* s = new S;
new (s) S; // UB:原S的生存期未显式结束(需先调用析构)

1.5、声明与定义

声明(Declaration) 和 定义(Definition) 是两个核心概念,它们的区别直接影响代码的编译和链接过程。

1.5.1、声明

声明的主要作用是向编译器介绍某个标识符(如变量、函数、类等)的存在,告知编译器该标识符的名称、类型和一些基本属性,但并不为其分配内存或实现具体的功能。

声明的用途是解决编译时的符号引用。

以下情况是声明

  • 变量声明:用extern关键字且不带初始化器
extern const int a;
  • 类定义中的非 inline(C++17 起) 静态数据成员的声明
struct S
{int n;               // 定义 S::nstatic int i;        // 声明 S::iinline static int x; // 定义 S::x
};                       // 定义 S
int S::i;                // 定义 S::i
  • 函数声明:仅提供签名
void foo(int a);
  • 类/类型声明:
class MyClass;
enum Color : int;
  • typedef 声明,using 声明
typedef S S2;   // 声明但不定义 S2(S 可以是不完整类型)
using S2 = S;   // 声明但不定义 S2(S 可以是不完整类型)
using N::d;     // 声明,引入一个已存在的名称,所以N::d必须已经被声明

重要:声明可多次重复(同一作用域内允许多次声明),但是声明必须完全一致

extern int x;     // 声明1
extern double x;  // 错误:类型不一致

函数声明可能分散在多个头文件中,最终在源文件中定义

// utils.h
void helper();// math.h
void helper(); // 重复声明(合法)// utils.cpp
void helper() {} // 唯一定义

1.5.2、定义

定义是为标识符分配存储空间或提供完整实现。每个标识符必须有且仅有一个定义(One Definition Rule, ODR)。

定义的用途是解决链接时的具体实现。

  • 变量定义:
int x = 42; // 定义并初始化x(分配内存)
  • 函数定义
void foo(int a) { // 函数定义std::cout << a;
}
  • 类定义:完整描述成员和方法。
class MyClass {
public:void method() {}
};

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

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

相关文章

STM32的TIMx中Prescaler和ClockDivision的区别

Prescaler预分频&#xff0c;以笔者目前的学习程度来说&#xff0c;这个参数&#xff0c;一般来说是对主时钟进行分频后的计数器时钟。这个预分频后的时钟主要是用于的计数的。 这个主时钟&#xff0c;对于时基单元来说可以是内部时钟&#xff0c;也可以是外部时钟。一般来说我…

前端性能指标及优化策略——从加载、渲染和交互阶段分别解读详解并以Webpack+Vue项目为例进行解读

按照加载阶段、渲染阶段和交互阶段三个维度进行系统性阐述&#xff1a; 在现代 Web 开发中&#xff0c;性能不再是锦上添花&#xff0c;而是决定用户体验与业务成败的关键因素。为了全面监控与优化网页性能&#xff0c;我们可以将性能指标划分为加载阶段、渲染阶段、和交互阶段…

MySQL——1、数据库基础

数据库基础 1、安装MySQL2、什么是数据库3、数据库使用案例4、MySQL架构与SQL分类5、存储引擎 1、安装MySQL 1、更新软件包列表 sudo apt update2、查看MySQL安装包 apt list | grep mysql-server3、安装MySQL # 默认安装最新版 sudo apt install -y mysql-server4、启动My…

ET MailBoxComponent类(实体) 分析

MailBoxComponent 作用是&#xff0c;用来接收Actor消息&#xff0c;处理Actor消息。这个没有存储能&#xff0c;收到消息后立即就处理了。ParentInstanceId 是MailBox所在的实体InstanceIdMailBoxType MailBox类型MailBoxInvoker 分发消息的包装Add 方法&#xff0c;看名字是…

Weblogic SSRF漏洞复现(CVE-2014-4210)【vulhub靶场】

漏洞概述&#xff1a; Weblogic中存在一个SSRF漏洞&#xff0c;利用该漏洞可以发送任意HTTP请求&#xff0c;进而攻击内网中redis、fastcgi等脆弱组件。 漏洞形成原因&#xff1a; WebLogic Server 的 UDDI 组件&#xff08;uddiexplorer.war&#xff09;中的 SearchPublicR…

js应用opencv

思路&#xff1a; 第一步&#xff1a;直方图 第二步&#xff1a;获得直方图的波峰 第三步&#xff1a;波峰胜负10&#xff0c;高于或低于变红色 1.引用import cv from ‘techstark/opencv-js’; 2.vue代码 <div class"historyLeft2"><div style"relat…

用Python代码绘制动态3D爱心效果

引言 介绍Python在创意编程中的应用&#xff0c;特别是如何通过简单的代码实现视觉上的美感。引出本文将分享的爱心代码&#xff0c;并简要说明其实现原理。 爱心代码的基本实现 展示一个简单的Python代码示例&#xff0c;使用字符画的方式在控制台中绘制一个爱心图案。 pr…

使用Python开发经典俄罗斯方块游戏

使用Python开发经典俄罗斯方块游戏 在这篇教程中&#xff0c;我们将学习如何使用Python和Pygame库开发一个经典的俄罗斯方块游戏。这个项目将帮助你理解游戏开发的基本概念&#xff0c;包括图形界面、用户输入处理、碰撞检测等重要内容。 项目概述 我们将实现以下功能&…

兼顾长、短视频任务的无人机具身理解!AirVista-II:面向动态场景语义理解的无人机具身智能体系统

作者&#xff1a;Fei Lin 1 ^{1} 1, Yonglin Tian 2 ^{2} 2, Tengchao Zhang 1 ^{1} 1, Jun Huang 1 ^{1} 1, Sangtian Guan 1 ^{1} 1, and Fei-Yue Wang 2 , 1 ^{2,1} 2,1单位&#xff1a; 1 ^{1} 1澳门科技大学创新工程学院工程科学系&#xff0c; 2 ^{2} 2中科院自动化研究所…

【蓝桥杯省赛真题49】python偶数 第十五届蓝桥杯青少组Python编程省赛真题解析

python偶数 第十五届蓝桥杯青少组python比赛省赛真题详细解析 博主推荐 所有考级比赛学习相关资料合集【推荐收藏】1、Python比赛 信息素养大赛Python编程挑战赛 蓝桥杯python选拔赛真题详解

鸿蒙(HarmonyOS)应用开发入门教程

目录 第一章:鸿蒙系统简介 1.1 什么是鸿蒙系统? 1.2 鸿蒙系统架构 第二章:开发环境搭建 2.1 安装DevEco Studio 步骤1:下载与安装 步骤2:首次配置 步骤3:设备准备 2.2 创建第一个项目 第三章:鸿蒙应用开发基础 3.1 核心概念:Ability与AbilitySlice 示例代码…

VM中 ubuntu 网卡不显示

1.添加网卡配置 #sudo nano /etc/netplan/01-netcfg.yaml network:version: 2renderer: networkdethernets:ens33:dhcp4: trueens37:dhcp4: trueens38:dhcp4: true#保存后 sudo netplan apply2.查看网络状态 sudo systemctl start systemd-networkd sudo systemctl status sy…

阿克曼-幻宇机器人系列教程3- 机器人交互实践(Message)

上一篇文章介绍了如何通过topic操作命令实现与机器人的交互&#xff0c;本篇我们介绍如何通过Message&#xff08;即topic的下一级&#xff09;实现与机器人的交互。 和topic一样&#xff0c;首先在一个终端通过ssh命令登录机器人、启动机器人&#xff0c;然后打开另外一个终端…

Python 调试扩展版本兼容问题解决纪实

在 Python 开发中&#xff0c;调试工具的正常使用对效率至关重要。近期在公司项目中&#xff0c;便遇到了 Python 调试扩展与版本不兼容的问题。公司 ERP 服务器采用 Ubuntu 18.04 系统&#xff0c;其标配 Python 版本为 3.6&#xff0c;而常用的 Python Debugger 扩展对版本有…

React 第四十二节 Router 中useLoaderData的用途详解

一、前言 useLoaderData&#xff0c;用于在组件中获取路由预加载的数据。它通常与路由配置中的 loader 函数配合使用&#xff0c;用于在页面渲染前异步获取数据&#xff08;如 API 请求&#xff09;&#xff0c;并将数据直接注入组件&#xff0c;从而简化数据流管理。 二、us…

Linux——mysql主从复制与读写分离

目录 一&#xff0c;理解什么是mysql主从复制 1&#xff0c;mysql支持的复制类型 2&#xff0c;mysql主从复制的工作流程 二&#xff0c;配置mysql主从复制 三&#xff0c;配置mysql主主复制 四&#xff0c;mysql读写分离 1&#xff0c;了解什么是mysql读写分离 2&…

MongoDB数据库深度解析:架构、特性与应用场景

在现代应用程序开发中&#xff0c;数据存储技术的选择至关重要。在众多的数据库管理系统中&#xff0c;MongoDB以其灵活性和强大的功能迅速崛起&#xff0c;成为NoSQL数据库中的佼佼者。本文将深入解析MongoDB的架构、核心特性、性能优化及其在实际应用中的最佳实践&#xff0c…

3D曲面上的TSP问题(一):曲面上点集距离求解

3D曲面上&#xff0c;两点的距离求解不能采用欧式距离&#xff0c;而需要计算测地线距离。 代码使用CGAL 5.6.2 OpenCV 4.11.0 版本实现 #include "cgal_utils.h" #include <CGAL/AABB_tree.h> #include <CGAL/AABB_traits.h> #include <CGAL/AABB_…

【歌曲结构】2:小节与歌曲结构信息整合

歌曲小节与结构信息整合 我将为您整合小节信息与歌曲结构,创建一个更加详细的JSON数据结构。 处理方法 将小节时间与歌曲结构段落进行匹配为每个小节添加所属段落信息为小节添加格式化的时间戳为小节添加对应时间范围内的歌词{"song_title": "财神庙前许三亿…

C语言:深入理解指针(3)

目录 一、数组名的理解 二、用指针访问数组 三、一维数组传参的本质 四、冒泡排序 五、二级指针 六、指针数组 七、指针数组模拟二维数组 八、结语 一、数组名的理解 数组名其实就是首元素的地址 int arr[3] {1,2,3}; printf("arr :%p\n" ,arr); printf(…