C++随心记

C++随心记

C++中的 CONST

C++中的const是表示不可修改

int main()
{/* 对于变量而言 */// 不可修改的常量const int A = 10;// 不可修改的指针指向const int* pointer_0 = nullptr;int const* poniter_1 = nullptr;// 不可修改指针指向的内容int* const poniter_2 = nullptr;
}

const也可修饰函数

class Entity
{
private:int* pointer;int x;
public:/* 对于函数而言 */// 修饰函数,使得其权限仅为读取,不可写入int GetX() const{// x++; 此语句是非法的,函数被const修饰后不准更改函数外的变量return x;}// 如果返回的为指针也可以用于修饰指针// 指向内容不可变int* const GetPoniter(){return pointer;}// 指向不可变const int* GetPointer(){return pointer;}// 一次性写最多的合法constconst int* const GetPointer() const{return pointer;}};

C++中的mutable

和上文的const一样,都是关键字,但mutable与const相反。mutable意味着可更改的。

class Entity
{
private:mutable int x;int y;
public:Entity(): x(10), y(20){}void ChangeXAndRead() const{x++;std::cout << "The value of X,Y is " << x << ',' << y << std::endl;// 这里的输出结果为11,20// 当试图修改y的值的时候,因为y的值为非mutable修饰,所以会报错}
};

C++中的成员初始化列表

在面向对象的语言中,多数程序员喜欢在构造器内初始化成员。在C++语法中,存在专门初始化成员的功能,此功能的优点是:避免了在定义成员时被构造,当我们定义一个变量时,如果这个变量为某个类的实例,那么在定义时会调用其构造器,当我们赋值时回再次调用构造器,这造成了性能的浪费。

class Entity
{
public:std::string x;  // 此时调用了string的构造器Entity(){x = "Hello";    // 此时调用了"Hello"的构造器,并把地址给了x}
};// 下面是一个比较直观的例子
class Example
{
public:Exapmle(){std::cout << "Example created!" << std::endl; }Example(int x){std::cout << "Example created with x! x=" << x << std::endl; }
};class Entity
{
public:Example example;// 这里会输出Example created!Entity(){example = Example(8);// 这里会输出Example created with x! x=8}
};

这样就输出了两次,代表着调用了两次构造器。为了节省性能,我们可以使用成员初始化列表,语法如下

class Entity
{
private:std::string m_Name;int m_DebugCount;
public:Entity(const std::string& Name):m_Name(Name), m_DebugCount(0){}
};

上面写了一个有参构造器,参变量为常量引用的Name。重点是下面是成员初始化列表,用冒号隔开,冒号后为要初始化的成员,初始化的内容为后面的括号的内容。需要注意的是,成员初始化列表需要和成员变量的定义顺序相同,这一规则非严格规定,但不遵守此规则可能会导致部分成员变量无法初始化!每个成员变量之间用逗号隔开

delete的小注意

对于new出来的对象,要记得delete。要delete一块数组,要用delete[]

int main()
{int* a = new int[10];delete[] a; // To delete array areturn 0;
}

如果不使用delete[]的话,你删的只是指针所指的第一个元素而已。

C++的隐式类型转换

C++中的类型转换是自动的,甚至可以转换到类的构造器中,以下为实例。

class Entity
{
private:int m_Age;std::string m_Name;
public:Entity(const std::string& name):m_Age(-1), m_Name(name){std::cout << "Entity constructor with name has called!" << std::endl;}Entity(int age):m_Age(age), m_Name("Unknown"){std::cout << "Entity constructor with age has called!" << std::endl;}
};int main()
{Entity e1 = 12; // 隐式类型转换Entity e2 = std::string("Chreno");return 0;
}

explicit关键字

由于隐式转换是默认的,开发者不希望自己的构造函数被隐式转换就可以添加关键字explicit来强制构造器拒绝隐式转换。例如

class Entity
{
private:int m_Age;std::string m_Name;
public:Entity(const std::string& name):m_Age(-1), m_Name(name){std::cout << "Entity constructor with name has called!" << std::endl;}explicit Entity(int age):m_Age(age), m_Name("Unknown"){std::cout << "Entity constructor with age has called!" << std::endl;}
};int main()
{// Entity e1 = 12; // 此行由于构造器被explicit修饰故报错Entity e2 = std::string("Chreno");return 0;
}

C++中的运算符重载

浅谈一下重载问题,其实运算符最简单的四则运算无非就是加减乘除。我们在重载时只要跟编译器说明了这个函数就是在重载就好了,我们会用到operator标识一下我们重载的是运算符

struct Vector2
{float x, y;Vector2(float x, float y):x(x), y(y) {}// 运算符重载Vector2 operator+(const Vector2& other) const{return Vector2(x + other.x, y + other.y);}Vector2 operator-(const Vector2& other) const{return Vector2(x - other.x, y - other.y);}Vector2 operator*(const Vector2& other) const{return Vector2(x * other.x, y * other.y);}Vector2 operator/(const Vector2& other) const{return Vector2(x / other.x, y / other.y);}Vector2 Add(const Vector2& other) const{return Vector2(x + other.x, y + other.y);}Vector2 Multiply(const Vector2& other) const{return Vector2(x * other.x, y * other.y);}void printSelf(){std::cout << "Value of x:" << x << ",Value of y:" << y << std::endl;}
};int main()
{Vector2 position(4.0f, 4.0f);Vector2 speed(0.5f, 1.5f);Vector2 powerup(1.1f, 1.1f);Vector2 result = position.Add(speed.Multiply(powerup));Vector2 res = position + speed * powerup;result.printSelf();res.printSelf();// result equals resreturn 0;
}

再补充一点,我们可以重载ostream的<<运算符来达到输出内容的目的

#include <iostream>class Entity
{
public:int x, y;Entity(int x, int y):x(x), y(y){}};// 2、此时我们就需要重载一下运算符
std::ostream& operator<<(std::ostream& stream, const Entity& other)
{stream << other.x << ',' << other.y << std::endl;return stream;
}int main()
{Entity e(1, 2);// std::cout << e << std::endl; // 1、这里肯定不会输出其内容,而且也会报错// 3、然后我们再来使用这个运算符std::cout << e << std::endl;return 0;
}

C++智能指针

智能指针就是用std::unique_ptr<>来裹住一个对象,相对于原始指针,智能指针加了一层壳。将这个对象的栈和堆内存绑定,在跳出作用域时自动调用delete方法,语法见下

#include <iostream>
#include <memory>class Entity
{
public:int x, y;Entity(int x, int y):x(x), y(y){std::cout << "Entity created!" << std::endl;}~Entity(){std::cout << "Entity destory by itself" << std::endl;}};int main()
{{std::unique_ptr<Entity> entity = std::make_unique<Entity>();    // 就一次内存分配,更效率std::unique_ptr<Entity> e(new Entity(1, 2));    // 先Entity()构造分配一次内存,再给unique_ptr分内存}std::cout << "Program is going done~" << std::endl;return 0;
}

但是unique_ptr不能共享指针给别人,从原理上来说,这个对象被释放以后手握这个对象的指针也都会嗝屁,实际上需要同步。从源码上来看,=号这个运算符被重载了。
下面看一下shared_ptr,一个可以共享的智能指针

#include <iostream>
#include <memory>class Entity
{
public:int x, y;Entity(int x, int y):x(x), y(y){std::cout << "Entity created!" << std::endl;}~Entity(){std::cout << "Entity destory by itself" << std::endl;}void print(){std::cout << "The value of x:" << x << ",y:" << y << std::endl;}
};int main()
{std::shared_ptr<Entity> e;{std::shared_ptr<Entity> shared_entity = std::make_shared<Entity>(); // 性能缘由同上std::shared_ptr<Entity> shared_entity_new(new Entity(1, 2));e = shared_entity;}e->print();std::cout << "Program is going done~" << std::endl;return 0;
}

shared_ptr底层实现类似计数器,不分享的时候相当于在unique_ptr和计数器=0,分享一次就会计数器++。当计数器为0后,再结束生命周期就会delete这个对象本体(在堆上),否则只是释放了指针本身的内存(在栈上)。给weak_ptr分享不会增加计数器。

C++计算偏移量

计算偏移量在计算机图形学里比较多见,先写一下具体过程

#include <iostream>struct Vector3
{float x, y, z;
};int main()
{int offset = (int)&((Vector3*)nullptr)->y;std::cout << offset << std::endl;std::cin.get();return 0;
}

代码中offset就是偏移量。首先将0或者nullptr强制转化为结构体或类的指针,再去通过->调用指针就会根据偏移量偏移到目标的起始位置(这就是我们需要的值),之后取这个位置的地址(因为使用0或者nullptr作为起始地址所以不用再考虑起始地址)用&取地址(内存编号为偏移量),再通过(int)强制转换成整数就得到了偏移量

C++中优化std vector三个简单方法

我们先来写一段代码实验一下

#include <iostream>
#include <vector>struct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}// copy constructorVertex(const Vertex& vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout << "Copied!" << std::endl;}
};int main()
{std::vector<Vertex> vertices;vertices.push_back({ 1, 2, 3 }); //1号语句vertices.push_back({ 4, 5, 6 }); //2号语句vertices.push_back({ 7, 8, 9 }); //3号语句return 0;
}

这段代码中我们规定:Vertex结构体,每当被复制后就向控制台输出
经过实际运行后,这段代码一共输出了 6 行Copied,说明在添加到vector时Vertex被复制了六次。以下是流程:执行到1号语句时vertices的承载力为0,产生新的vertices并将旧的vertices复制到新的vertices中此时输出1次Copied,到二号语句,承载力不够,接着出现新的容器,旧的vertices中已经有的Vertex和新的Vertex都会被复制到新的容器中,此时复制了两次,即输出两次Copied,以此类推三号语句输出了三次Copied,最后即输出了1+2+3次即6次Copied
这段过程看似在计算机强大算力前不复杂,但是当push_back次数多了以后复制次数就会爆炸式增长

解决方案 一

先告诉vector给留多少空间,避免了多次复制

#include <iostream>
#include <vector>struct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}// copy constructorVertex(const Vertex& vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout << "Copied!" << std::endl;}
};int main()
{std::vector<Vertex> vertices;vertices.reserve(3);    // 预留空间vertices.push_back(Vertex(1, 2, 3));vertices.push_back(Vertex(4, 5, 6));vertices.push_back(Vertex(7, 8, 9));return 0;
}

在这里通过reserve告诉vector给我留3个单位的空间,运行完毕后仅输出了 3 次Copied,即没有新的容器创建

解决方案 二

通过调用类或者结构体的构造器,函数括号内为构造器对应参数

#include <iostream>
#include <vector>struct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}// copy constructorVertex(const Vertex& vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout << "Copied!" << std::endl;}
};int main()
{std::vector<Vertex> vertices;vertices.emplace_back(1, 2, 3);vertices.emplace_back(4, 5, 6);vertices.emplace_back(7, 8, 9);return 0;
}

此方法效率和法一相同,实现机制不同

解决方案 三(二 + 一)

预留好空间后再使用emplace不会产生任何复制(预留空间>=实际需求空间)

#include <iostream>
#include <vector>struct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}// copy constructorVertex(const Vertex& vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout << "Copied!" << std::endl;}
};int main()
{std::vector<Vertex> vertices;vertices.reserve(3);vertices.emplace_back(1, 2, 3);vertices.emplace_back(4, 5, 6);vertices.emplace_back(7, 8, 9);return 0;
}

此示例Vertex类没有发生复制

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

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

相关文章

【湖南步联科技身份证】 身份证读取与酒店收银系统源码整合———未来之窗行业应用跨平台架构

一、html5 <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><script type"text/javascript" src"http://51.onelink.ynwlzc.net/o2o/tpl/Merchant/static/js…

pip外部管理环境错误处理方法

error: externally-managed-environment This environment is externally managed ╰─> To install Python packages system-wide, try apt install python3-xyz, where xyz is the package you are trying to install. sudo mv /usr/lib/python3.x/EXTERNALLY-MANAGED …

onload_tcpdump命令抓包报错Onload stack [7,] already has tcpdump process

最近碰到Onload 不支持同时运行多个 tcpdump 进程的报错&#xff0c;实际上使用了ps查询当时系统中并没有tcpdump相关进程存在。需要重启服务器本机使用onload加速的相关进程后才能使用onload_tcpdump正常抓包&#xff0c;很奇怪&#xff0c;之前确实没遇到这样的问题&#xff…

Golang | Leetcode Golang题解之第450题删除二叉搜索树的节点

题目&#xff1a; 题解&#xff1a; func deleteNode(root *TreeNode, key int) *TreeNode {var cur, curParent *TreeNode root, nilfor cur ! nil && cur.Val ! key {curParent curif cur.Val > key {cur cur.Left} else {cur cur.Right}}if cur nil {retur…

Django Nginx+uwsgi 安装配置

Django Nginx+uwsgi 安装配置 本文将详细介绍如何在Linux环境下安装和配置Django应用程序,使用Nginx作为Web服务器和uwsgi作为应用程序服务器。我们将覆盖以下主题: 安装Python和相关库安装和配置Django安装Nginx安装和配置uwsgi配置Nginx以使用uwsgi测试和调试1. 安装Pytho…

金镐开源组织成立,增加最新KIT技术,望能为开源添一把火

国内做开源的很多&#xff0c;知名的若依、芋道源码、Pig、Guns等&#xff0c;可谓是百花齐放&#xff0c;虽然比不上Apache&#xff0c;但也大大提高了国内的生产力。经过多年的发展&#xff0c;一些开源项目逐渐也都开始商业化。基于这样的背景&#xff0c;我拉拢了三个技术人…

【重学 MySQL】三十九、Having 的使用

【重学 MySQL】三十九、Having 的使用 基本语法示例示例 1&#xff1a;使用 HAVING 过滤分组示例 2&#xff1a;HAVING 与 WHERE 的结合使用 注意点WHERE 与 HAVING 的对比基本定义与用途主要区别示例对比总结 在 MySQL 中&#xff0c;HAVING 子句主要用于对 GROUP BY 语句产生…

使用powershell的脚本报错:因为在此系统中禁止执行脚本

1.添加powershell功能环境&#xff1a; 2.启动powershell的执行策略 因为在此系统中禁止执行脚本。 set-executionpolicy unrestricted

【计算机视觉】ch1-Introduction

相机模型与成像 1. 世界坐标系 (World Coordinate System) 世界坐标系是指物体在真实世界中的位置和方向的表示方式。在计算机视觉和图像处理领域&#xff0c;世界坐标系通常是一个全局坐标系统&#xff0c;描述了摄像机拍摄到的物体在实际三维空间中的位置。它是所有其他坐标…

刷题day11 栈与队列下【逆波兰表达式求值】【滑动窗口最大值】【前 K 个高频元素】

⚡刷题计划day11 栈与队列继续&#xff0c;可以点个免费的赞哦~ 往期可看专栏&#xff0c;关注不迷路&#xff0c; 您的支持是我的最大动力&#x1f339;~ 目录 ⚡刷题计划day11 栈与队列继续&#xff0c;可以点个免费的赞哦~ 往期可看专栏&#xff0c;关注不迷路&#xf…

无心剑七绝《华夏中兴》

七绝华夏中兴 长空万里尽春声 治世群英喜纵横 一代雄才华夏梦 中兴日月照前程 2024年10月1日 平水韵八庚平韵 无心剑的七绝《华夏中兴》通过对自然景观和国家景象的描绘&#xff0c;展现了一种恢弘的气势和对未来的美好愿景。 意境开阔&#xff1a;首句“长空万里尽春声”以广阔…

MATLAB数字水印系统

课题介绍 本课题为基于MATLAB的小波变换dwt和离散余弦dct的多方法对比数字水印系统。带GUI交互界面。有一个主界面GUI&#xff0c;可以调用dwt方法的子界面和dct方法的子界面。流程包括&#xff0c;读取宿主图像和水印图像&#xff0c;嵌入&#xff0c;多种方法的攻击&#xf…

跳台阶问题

剑指offer的一道简单题目。 描述 一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法&#xff08;先后次序不同算不同的结果&#xff09;。 数据范围&#xff1a;1≤n≤40 要求&#xff1a;时间复杂度&#xff1a;O(n) &a…

C#和Python共享内存技术

我这里做一个简单的示例 1.C#写入内存的方法&#xff0c;FileName是内存共享的名字 t是内存size public static void SaveGluePLYToMemory(string FileName, string msg){try{ long t 100;// SetMemorySize(msg);// 100;//# 创建内存块&#xff0c;test1,其他语言利用这个内存…

sysbench 命令:跨平台的基准测试工具

一、命令简介 sysbench 是一个跨平台的基准测试工具&#xff0c;用于评估系统性能&#xff0c;包括 CPU、内存、文件 I/O、数据库等性能。 ‍ 比较同类测试工具 bench.sh 在上文 bench.sh&#xff1a;Linux 服务器基准测试中介绍了 bench.sh 一键测试脚本&#xff0c;它对…

Python库pandas之一

Python库pandas之一 基本数据结构Series构造器属性属性应用函数函数应用 基本数据结构 Pandas提供了两种类型的类来处理数据&#xff1a; Series&#xff1a;保存任何类型数据的一维数组。例如整数、字符串、Python对象等。DataFrame&#xff1a;一种二维数据结构&#xff0c…

ip是可以从能够上网的设备提取吗

是的&#xff0c;IP地址可以从能够上网的设备提取。以下是如何从不同设备提取IP地址的具体方法&#xff1a; 在电脑上提取IP地址 Windows: 打开命令提示符&#xff08;按下 Win R&#xff0c;输入 cmd&#xff0c;按回车&#xff09;。 输入命令 ipconfig&#xff0c;按回车。…

GAMES101(17~18节,物理材质模型)

材质 BRDF 材质&#xff1a;决定了光线与物体不同的作用方式 BRDF定义了物体材质,包含漫反射和镜面部分 BSDF &#xff08;scattering散射&#xff09; BRDF&#xff08;reflect反射&#xff09; BTDF 光线打击到物体上会向四面八方散射 反射 光线打击到物体上反射出去…

IIS开启后https访问出错net::ERR_CERT_INVALID

安装ArcGIS server和portal等&#xff0c;按照说明上&#xff0c;先开启iis&#xff0c;在安装server、datastore、portal、webadapter等&#xff0c;遇到一些问题&#xff1a; 问题1 访问http正常&#xff0c;访问https出错&#xff1a; 解决方案 从这里找到解决方案&…

【Android 源码分析】Activity生命周期之onPause

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…