C++中的非常规关键字使用的总结

news/2024/4/19 16:07:49/文章来源:https://blog.csdn.net/a486259/article/details/129159534

cpp中的非常规关键字(在一般小项目编程中不会刻意用到的关键字)有很多,使用这些非常规的关键字,目的就是三点:一、使代码变的更加灵活(如指针、template关键字、宏语法);二、使代码变得更加严谨(如const、static、explicit、virtual等,可消除在代码互动中的歧义和误改动,约束程序员对代码的用法,并消除在代码执行期间的bug);三、是代码执行更高效(如final、noexcept、constexpr等),让编译器在编译代码时可根据代码关键字进行优化。这里对cpp中的非常规关键字使用进行总结,具体包含:std指针、inline|static|final|const|typedef等一般关键字、define的用法、template的用;此外,还包括:constexpr、explicit、virtual、noexcept等特殊关键字的用法。

此外,c++还有更多的关键字,如关于变量的关键字(register[寄存器变量,更快的读取速度]、volatile[防止编译器优化,保持内存可见性])等(告诉编译器该变量的位置、是否需要进行优化)。具体可以参考https://blog.csdn.net/Jochebed666/article/details/90613927

1、std指针

在std库的中有auto_ptr,unique_ptr,shared_ptr和weak_ptr四种指针,在后续升级中auto_ptr智能指针被抛弃了(容易产生内存泄漏,auto_ptr a1赋值给auto_ptr a2后,同一个内存地址在auto_ptr的析构函数中会被释放两次)。

//声明
std::shared_ptr<Ort::Env>env;
//赋值
env.reset(new Ort::Env(ORT_LOGGING_LEVEL_WARNING, env_name.c_str()))
//释放
env->release();

具体可以参考 https://blog.csdn.net/love10_1314/article/details/94740707

std::ptr_fun(),将一个普通函数包装成函数对象。此函数与关联类型从 cpp11 起被弃用,被更通用的 std::function 和 std::ref 所替代。
cpp11 替用方案 :
可将 std::not1(std::ptr_fun(isvowel)) 改为 std::not1(std::cref(isvowel)) 或者 std::not1(std::function<bool(char)>(isvowel))
https://www.jianshu.com/p/1bbd8bac9fbb

2、关键字

inline修饰符

用于修饰函数的实现代码,表示为内联函数(用于避免 频繁调用的小函数大量消耗栈空间【栈内存】的问题),既在编译时代码在调用点展开(不从栈内存中加载函数)。inline修饰的函数是不能进行递归调用的,其本身只是带编译器的一个建议(编译器会自动根据函数的复杂程度决定是否要真正实现内联)。定义在类中的成员函数(被class{}包裹实现的函数)默认都是内联的;inline时一种用于描述实现的关键字,不能放在函数声明上。具体参考 https://www.runoob.com/w3cnote/cpp-inline-usage.html

static修饰符

在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次(多次调用函数,其内部的static初始化只执行一次),而且延长了局部变量的生命周期(要在运行结束以后才释放);static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。
在面向对象中,被 static 修饰的变量属于类变量,static 修饰的方法属于类方法,可以直接通过类名调用,不需要new出新实例;同时,被static 修饰的变量和函数在类级别是全局共享的。具体参考 https://www.runoob.com/w3cnote/cpp-static-usage.html

final修饰符

用于表示该修饰对象处于最终状态,不可以被再度修改(如修饰class时表示该类不可以被继承;修饰虚函数时表示该类不可以被重载)。可以包含特定类或函数,在实际使用中还可以用 final修饰虚函数,以提升代码执行性能(在动态绑定时[父类指针指向子类],一个类或函数声明成final,在编译器层面可以优化掉一步vtable的查找开销,这在cpp的标准中并没有规定,完全依赖于编译器的实现。)具体参考 https://zhuanlan.zhihu.com/p/104210081

const修饰符

const 是 constant 的缩写,本意是不变的,不易改变的意思。cpp const 允许指定一个语义约束,编译器会强制实施这个约束,允许程序员告诉编译器某值是保持不变的。如果在业务过程中有某个变量在初始化后就不能被修改,就应该明确使用const,这样可以获得编译器的帮助。 具体参考https://www.runoob.com/w3cnote/cpp-const-keyword.html

与const修饰相对应的是volatile修饰,表示该变量是经常被改变的,该关键字的作用是防止编译器优化时把变量从内存装入 CPU 寄存器中(CPU寄存器加载变量速度比内存快)。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile 的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值。

typedef

使用关键字 typedef 可以为类型起一个新的别名。typedef 的用法一般为:

typedef  oldName  newName;

typedef 还可以给数组、指针、结构体等类型定义别名,具体例子如下所示:

typedef char ARRAY20[20];
ARRAY20 a1, a2, s1, s2;  //与下面一行等价
char a1[20], a2[20], s1[20], s2[20];

typedef 在表现上有时候类似于 #define,但它和宏替换之间存在一个关键性的区别,更多参考http://c.biancheng.net/view/2040.html

3、define的用法

又称为宏定义,其本质是实现字符串替换,可以用于实现各种常量、简单函数的定义。
其中关于宏函数(相比于函数调用可节省一定时间)实现max、min的效果可以参考 https://blog.csdn.net/Sleepp/article/details/81876502
利用宏函数实现字符串连接,在宏语法中 a ## b 的结果为ab,表示为连接

#define ACCESS _access
#define symbol  '\\'
#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))
#define SLEEP Sleep(1000)
#define mkdirs(path) _mkdir(path)
#define concat( x, y )  x ## y

条件编译,可以用于针对不同的的操作系统执行不同的代码

#ifdef WIN32
code for windows
#else
code for linux
#endif

可以用于避免hpp头文件函数实现被多次导入(#pragma once也是描述该头问题只用导入一次)

#ifndef __WebFun__
#define __WebFun__
#pragma oncecode#endif

在代码上指定添加某静态库

#pragma comment( lib, "opencv.lib" )   //指定与静态库一起连接

4、template的用法

template 是cpp中用于定义模板的固定格式。模板是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性。模版可以分为两类,一个是函数模版,另外一个是类模版。内容完全参考 LabVIEW_Python http://events.jianshu.io/p/90bad1ef3431

函数模板

可实现函数的泛化,避开函数类型的强制声明

//数据类型T 参数化数据类型
template <typename T>
void generic_swap(T& a, T& b)
{T tmp;tmp = b;b = a;a = tmp;
}
int main()
{int a = 100, b = 50;generic_swap(a, b);cout << "excute the swap():" << a << " : " << b << endl;char c = 'A', d = 'B';generic_swap(c, d);cout << "excute the swap():" << c << " : " << d << endl;string e = "Jacky", f = "Lucy";generic_swap(e, f);cout << "excute the swap():" << e << " : " << f << endl;double j = 1.314, k = 5.12;generic_swap(j, k);cout << "excute the swap():" << j << " : " << k << endl;return 0;
}

类模板

可在一个类函数中声明多个类模板,用于支持灵活调用,常见于vector、vector、vector等的使用,既在实例化对象后要显性的指定模板类型。

#include<iostream>
#include<string>
using namespace std;//注意:模板头和类头是一个整体,可以换行,但是中间不能有分号
template<typename T1, typename T2>  //这里不能有分号
class Point {
public:Point(T1 x, T2 y) : m_x(x), m_y(y) { }
public:T1 getX() const;  //获取x坐标void setX(T1 x);  //设置x坐标T2 getY() const;  //获取y坐标void setY(T2 y);  //设置y坐标
private:T1 m_x;  //x坐标T2 m_y;  //y坐标
};//下面就对 Point 类的成员函数进行定义
template<typename T1, typename T2> T1 Point<T1, T2>::getX() const {return m_x;
}template<typename T1, typename T2> void Point<T1, T2>::setX(T1 x) {m_x = x;
}template<typename T1, typename T2> T2 Point<T1, T2>::getY() const {return m_y;
}template<typename T1, typename T2> void Point<T1, T2>::setY(T2 y) {m_y = y;
}int main()
{// 与函数模板不同的是,类模板在实例化时必须显式地指明数据类型// 编译器不能根据给定的数据推演出数据类型Point<int, int> p1(10, 10);cout << "x=" << p1.getX() << ", y=" << p1.getY() << endl;Point<float, float> p2(12.88, 129.65);cout << "x=" << p2.getX() << ", y=" << p2.getY() << endl;Point<string, string> p3("E180","N210");cout << "x=" << p3.getX() << ", y=" << p3.getY() << endl;Point<int, float> p4(4, 129.65);cout << "x=" << p4.getX() << ", y=" << p4.getY() << endl;Point<string, int> p5("hello,world!", 5);cout << "x=" << p5.getX() << ", y=" << p5.getY() << endl;//除了对象变量,我们也可以使用对象指针的方式来实例化Point<string, int>* p7 = new Point<string, int>("hello,world!", 7);// (pointer_name)->(variable_name)// The Dot(.) operator is used to normally access members of a structure or union.// The Arrow(->) operator exists to access the members of the structure or the unions using pointerscout << "x=" << p7->getX() << ", y=" << p7->getY() << endl;delete p7;return 0;
}

可变参模板

一个简单的可变模版参数函数,在声明时使用class… T,在实际使用中用T… args表示可传入多个参数。

template <class... T>
void f(T... args)
{    cout << sizeof...(args) << endl; //打印变参的个数
}f();        //0
f(1, 2);    //2
f(1, 2.5, "");    //

基于可变模板参数函数,实现递归函数(如实现sum、max等功能,有或者实现传入多个参数的功能)。以下代码中sum(rest…)函数一开始在多个参数时是执行的函数2,直到参数被不断拆解到最后一个时才执行函数1.

//函数1  递归终止函数
template<typename T>
T sum(T t)
{return t;
}
//函数2 持续递归函数
//通过这种写法,每次递归都会拆解一个参数到a1中
template<typename T, typename ... Types>
T sum (T a1, Types ... rest)
{return a1 + sum<T>(rest...);
}
sum(1,2,3,4); //10

本节内容参考 https://blog.csdn.net/wmy19890322/article/details/121427697

5、特殊关键字

constexpr

constexpr-》常量表达式,指的就是由多个(≥1)常量组成的表达式。换句话说,如果表达式中的成员都是常量,那么该表达式就是一个常量表达式。这也意味着,常量表达式一旦确定,其值将无法修改。

// 1)
int url[10];//正确
// 2)
int url[6 + 4];//正确
// 3)
int length = 6;
int url[length];//错误,length是变量

explicit

explicit-》阻止对象只有一个参数时的的隐式初始化,用于类内的单参数构造函数前面。由于无参数的构造函数和多参数的构造函数总是显示调用,这种情况在构造函数前加explicit无意义。用于禁止编译器执行非预期(往往也不被期望)的类型转换(限制编译器的智能推断)

#include <iostream>
using namespace std;
class Test1
{
public :Test1(int num):n(num){}
private:int n;
};
class Test2
{
public :explicit Test2(int num):n(num){}
private:int n;
};int main()
{Test1 t1 = 12;//隐式调用Test1(12),完整等效代码为Test1 t1 = Test1(12);Test2 t2(13);Test2 t3 = 14;//隐式调用Test1(12),被explicit关键字拦截,然后报错return 0;
}

virtual

virtual用于修饰父类中的函数(构造函数、static静态函数不能用virtual关键字修饰)。当父类函数A被virtual修饰后,父类指针指向的子类对象(子类重载了函数A),在调用函数A时(因为有virtual修饰)会响应父类的A函数。可以用于复杂继承关系时析构函数的修饰,避免多重继承时构造函数和析构函数的紊乱。可以用于修饰父类的析构函数,避免出现内存泄漏(最好别用父类指针指向子类),详情参考: https://blog.csdn.net/itlilyer/article/details/109274204

noexcept

该关键字告诉编译器,函数中不会发生异常,这有利于编译器对程序做更多的优化。一共有noexcept、noexcept(true)、noexcept(false)、noexcept(expression)四种写法(noexcept 默认表示 noexcept(true))。具体参考https://www.cnblogs.com/sword03/p/10020344.html。
单独使用noexcept|noexcept(true),表示其所限定的swap函数绝对不发生异常。然而,使用方式可以更加灵活,表明在一定条件下不发生异常。

void swap(Type& x, Type& y) throw()   //cpp11之前{x.swap(y);}
void swap(Type& x, Type& y) noexcept  //cpp11{x.swap(y);}

如果函数的返回值仅为true或false,甚至可以将函数体写入noexcept中,具体如下所示。

	bool IgnoreCaseCompare(const std::string& a, const std::string& b)noexcept{if (a.size() != b.size())return false;for (size_t i = 0; i < a.size(); i++){if (tolower(a[i]) != tolower(b[i]))return false;}return true;};

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

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

相关文章

stm32 VM8978 音乐播放

一、WAV文件 1、WAV文件简介 2、WAV文件的解析 二、WM8978 1、WM8978介绍 2、WM8978特点 3、WM8978接口 4、WM8978框架 5、 WM8978 寄存器 三、IIS详解 1、IIS介绍 2、 IIS 的特点 3、IIS框架 4、 音频协议 5、 IIS Philips 标准 6、 IIS 时钟 四、音乐播放硬件…

ChatGPT三个关键技术

情景学习&#xff08;In-context learning&#xff09; 对于一些LLM没有见过的新任务&#xff0c;只需要设计一些任务的语言描述&#xff0c;并给出几个任务实例&#xff0c;作为模型的输入&#xff0c;即可让模型从给定的情景中学习新任务并给出满意的回答结果。这种训练方式能…

双检测人脸防伪识别方法(活体检测+人脸识别+关键点检测+人像分割)

双检测人脸防伪识别=人脸检测+活体检测+人脸识别 1.人脸关键点+语义分割 使用mediapipe进行视频人脸关键点检测和人像分割: import time import cv2 import mediapipe as mp import numpy as npmp_drawing = mp.solutions.drawing_utils mp_drawing_styles = mp.solution…

量化交易-单因子分析-alphalens

1. 数据准备 1.1 计算因子IC重要函数 def get_clean_factor_and_forward_returns(factor,prices,groupbyNone,binning_by_groupFalse,quantiles5,binsNone,periods(1, 5, 10),filter_zscore20,groupby_labelsNone,max_loss0.35,zero_awareFalse,cumulative_returnsTrue)facto…

【C语言】-程序编译的环境和预处理详解-让你轻松理解程序是怎么运行的!!

作者&#xff1a;小树苗渴望变成参天大树 作者宣言&#xff1a;认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点 点 关 注 吧&#xff01; 程序的编译前言一、 程序的翻译环境和执行环境二、 详解翻译环境2.1编译环境2.1.1预编…

民锋国际期货:2023,既艰难又充满希望,既纷乱又有无数机会。

不管是官方还是民间&#xff0c;各种信号都表明&#xff0c;2023年是一个拼经济的年份。 通货膨胀带来的需求量的增加&#xff0c;与中国经济高速发展带来的供给量增加&#xff0c;二者共同构成了我们的物价。 做一个长期主义者&#xff0c;做一个坚定看好中国未来的人&#…

MapBox动态气泡图渲染教程

先来看效果: 视频效果: 屏幕录制2023-02-22 15.34.57 首先我们来介绍一下思路。对于mapbox和openlayers这样的框架来讲,气泡图中的气泡本质上就是一个div,就是将一个dom元素追加到canvas上的固定位置而已。 在mapbox中有marker的概念,官网也有示例: Attach a popup to …

二叉树——路径总和

路径总和 链接 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点…

数据库及缓存之MySQL(一)

思维导图 常见知识点 1.mysql存储引擎&#xff1a; 2.innodb与myisam区别&#xff1a; 3.表设计字段选择&#xff1a; 4.mysql的varchar(M)最多存储数据&#xff1a; 5.事务基本特性&#xff1a; 6.事务并发引发问题&#xff1a; 7.mysql索引&#xff1a; 8.三星索引&#xf…

升职加薪必备,2023年程序员不能不知道的AI辅助编码工具

已经有很多人把chatGPT当做必备的Bug修复工具了&#xff0c;对于用AI写代码&#xff0c;有人感到失落&#xff0c;害怕被取代&#xff0c;而另一些人则认为人工智能将加快编写更好代码的过程。 尽管 AI 编写的代码并非完美无缺&#xff0c;但我相信&#xff0c;最终AI将取代人…

车机开发—【CarService启动流程】

汽车架构&#xff1a;车载HAL是汽车与车辆网络服务之间的接口定义&#xff08;同时保护传入的数据&#xff09;&#xff1a; 车载HAL与Android Automotive架构&#xff1a; Car App&#xff1a;包括OEM和第三方开发的AppCar API&#xff1a;内有包含CarSensorManager在内的AP…

Hadoop集群模式安装(Cluster mode)

1、Hadoop源码编译 安装包、源码包下载地址 Index of /dist/hadoop/common/hadoop-3.3.0为什么要重新编译Hadoop源码? 匹配不同操作系统本地库环境&#xff0c;Hadoop某些操作比如压缩、IO需要调用系统本地库&#xff08;*.so|*.dll&#xff09; 修改源码、重构源码 如何…

H12-831题库(有详细的解析)

1.&#xff08;单选&#xff09;某工程师利用2台路由器进行IPv6业务测试,通过运行BGP4模拟总部与分支的互联互通。如图所示,某工程师抓包查看R1发出的update报文。关于该报文信息的描述,以下哪个说法是正确的? A.该报文描述的路由的下一跳地址为:2001:db8::2345:1::1 B.该报文…

自动增长配置不合理导致的性能抖动

背景客户收到了SQL专家云告警邮件&#xff0c;在凌晨2点到3点之间带有资源等待的会话数暴增&#xff0c;请我们协助分析。现象登录SQL专家云&#xff0c;进入活动会话的趋势分析页面&#xff0c;下钻到2点钟一个小时内的数据&#xff0c;看到每分钟的等待数都在100左右&#xf…

关于upstream的八种回调方法

1 creat_request调用背景&#xff1a;用于创建自己模板与第三方服务器的第一次连接步骤1&#xff09; 在Nginx主循环&#xff08;ngx_worker_process_cycle方法&#xff09; 中&#xff0c;会定期地调用事件模块&#xff0c; 以检查是否有网络事件发生。2&#xff09; 事件模块…

人员行为识别系统 TensorFlow

人员行为识别系统人员行为识别系统通过TensorFlow深度学习技术&#xff0c;人员行为识别算法对画面中区域人员不按要求穿戴、违规抽烟打电话、睡岗离岗以及作业流程不规范实时分析预警&#xff0c;发现违规行为立即抓拍告警。深度学习应用到实际问题中&#xff0c;一个非常棘手…

快速读懂网络拓扑图

快速读懂网络拓扑图几重常见的网络拓扑总线型拓扑简介优点缺点环型拓扑简介优点缺点星型拓扑简介优点缺点网络层级机构节点结点链路通路不同的连接线代表什么意思&#xff1f;不同颜色、粗细的直线代表什么意思&#xff1f;闪电线-串行链路几重常见的网络拓扑 总线型拓扑 简介…

浅谈volatile关键字

文章目录1.保证内存可见性2.可见性验证3.原子性验证4.原子性问题解决5.禁止指令重排序6.JMM谈谈你的理解6.1.基本概念6.2.JMM同步规定6.2.1.可见性6.2.2.原子性6.2.3.有序性6.3.Volatile针对指令重排做了啥7.你在哪些地方用过Volatile&#xff1f;volatile是Java提供的轻量级的…

【华为OD机试模拟题】用 C++ 实现 - 求字符串中所有整数的最小和

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

【Git】Git的分支操作

目录 4、 Git 分支操作 4.1 什么是分支 4.2 分支的好处 4.3 分支的操作 4、 Git 分支操作 4.1 什么是分支 在版本控制过程中&#xff0c; 同时推进多个任务&#xff0c; 为每个任务&#xff0c; 我们就可以创建每个任务的单独分支。 使用分支意味着程序员可以把自己的工作…