Latest

C++系列

[Cpp基础][11]"异常"

异常 * C++内所说的异常是指:可以预见的非正常状况,例如输入的指针为空;而非不可预见的问题,例如突然停电,或者突然被用户把进程kill掉,并不是C++需要处理的"异常" * 异常特性会导致程序的执行流程不可控,且往往对OS及runtime有一定的要求(可移植性差),所以没有特殊需求时,不应当使用这个特性. * throw-try-catch是异常系统的典型三个环节. * throw出的可以是任意对象,只要catch处声明的对象可以用throw的对象初始化即可.习惯上我们会专门设计一个类,因为自定义类可以承载更多的信息 * 异常catch中的形参可以使用引用,以使用多态机制 * 异常抛出后寻找catch的过程称为栈展开,被展开的函数栈内所有局部对象都将被销毁,因此抛出的异常对象必须不依赖局部对象. * 标准库内提供了以exception为基类的若干异常,我们可以使用这个类,也可以自定义类,该类的const char * what()成员用于给用户提供信息. * catch时,优先使用引用, 从而保证能派生类实例能绑定到基类参数上

By Edimetia3D

C++系列

[Cpp基础][10]重载运算符

重载运算符 规定 * 赋值,取下标,调用,箭头,类型转换,这些运算符只能作为成员函数. * 用户重载的&&与||不会进行短路求值. 习惯 * 重载主要分为全局重载和类内重载,一般而言,二元运算都应该在全局重载(顺序问题). * 改变对象状态的运算符一般应当设为成员函数,拥有对称性的运算符一般应在类外重载. * 从技术层面说,重载运算符的参数可以是指针类型的,但是这一般与我们使用语言的习惯不符,所以形参类型最好只是T或T&,而不要是指针. * 定义有关联的重载运算符时一定要考虑兼容性,例如a<b为假,a>b也为假,那么a==b就应该返回真. * 重载中应当尽可能的保持语义与内置风格一致. * 例如,如果重载了++运算符,那么应当保证++x和x+=1及x=x+1有同样的效果. * 尽量不要重载全局的operator new,仅在类内重载它. * 类内重载的new和delete都是static的,因此,无法使用this相关的量

By Edimetia3D

记录

从宿主访问Ubuntu虚拟机的文件

背景: 开发中希望能从宿主直接访问虚拟机的文件,例如用office打开word,用 source insight 阅读代码等。 * 虚拟机为16.04 ,宿主为Windows 10 1803,samba试了很多次,就是不行。 * ftp方案: 1. sudo apt-get install vsftpd 2. sudo vi /etc/vsftpd.conf,并在末尾粘贴以下内容 anonymous_enable=YES anon_root= abs_path_to_dir no_anon_password=YES write_enable=YES anon_upload_enable=YES anon_mkdir_write_

By Edimetia3D

C++系列

[Cpp基础] [08] 动态内存与智能指针

动态内存与智能指针 new+delete * new delete是C++中的两个主要的表达式. * new相当于C的malloc() + T(),delete相当于C的free() + ~T(). * operator new()以及operator delete()仅能用于覆盖内存分配操作,构造和析构的调用是无法被替换的. * delete能否正常执行依赖于指向的对象能否delete,而不依赖于指针自身(指针类型不含任何额外信息). * new T[n]中,n可以为0,返回的将是一个不能解引用的指针值,该指针值保证非nullptr,可以做正常的比较. * new和delete表达式总是会触发构造和析构,必要时可以使用malloc+placement new方案进行更精细的控制. * placement new仅仅用于在特定地址上触发构造函数, 后续需要手动调用析构函数来销毁对象. shared_ptr与unique_ptr * 智能指针都不是为数组型数据设计的,所以都没有重载[],+,-等运算符.

By Edimetia3D

C++系列

[Cpp基础] [07] 复杂类型和类型推断

数组类型和函数类型 尽管在大部分场合中,数组类型和函数类型都被转换成某种指针使用,然而它们确实是某种类型. 这一点在类型推导中很重要,因为类型推导可以推导出数组类型/函数类型 * 数组类型逻辑上类似于std::array,由T和N两个属性决定唯一的数组类型,称T[N]型对象为数组类型,其中N必须为constexpr,称T array[N]为T[N]的一个实例. * T和N必须都相同才是同一个array类型. * 数组类型可以被隐式decay为指向数组首元素的指针. * 转换为指针后,长度信息就丢失了. * 在T[N]做函数形参时,编译器一定会将形参转换为指针,从而可以接受长度不同的数组,长度信息也随之丢失. * 数组的长度信息未丢失时,编译器及用户是可以获取到这些长度信息的.sizeof(array)/sizeof(array[0])就是元素数量. * 可以使用引用型形参来保留数组的长度信息,对于模板,还可以使用自动推断. * 自动推断:template<class T>fun(T &

By Edimetia3D

C++系列

[Cpp基础] [06] 强制类型转换

* C++风格的类型转换有四种,每个都有特定的应用场合.转换可以分为隐式或显式的,显式转换也被称为强制类型转换. * 隐式类型转换语义上只能对应static_cast或const_cast二者其一. * 规定:仅有xxx_cast<TYPE &>(var)整体可以作为左值,其他情况转换得到的都是右值临时对象。 强制类型转换 const_cast * const_cast是只用于处理const相关的类型转换,主要是移除const(加const完全可以用隐式转换), const_cast只有向引用/指针的转换有实际意义. const T c_obj; const T * p_c_obj=&c_obj; const T * const cp_c_obj=p_c_obj; T&

By Edimetia3D

C++系列

[Cpp基础] [05] const与constexpr

Const Expression, constexpr 是一个非常复杂的话题, 幸运的是, 我们在实践中 需要记住的内容并不太多,因为常见的应用场景其实比较简单. const限定符 * const是一种编译期特性,用于限定对象的编译期写入权限, 编译器也可能将const对象视作constexpr进行优化. * 理论上可以通过各种trick在运行期写入对象,但是不要这么做. * 当项目很大,或者开发人员很多时,使用const就能利用编译器约束开发人员的行为,给开发人员做一定提醒. * 原则上,当我们创建一个变量时,若认为它不应当被修改,就应当声明称const型.最常用的场合是函数形参/返回值中的const T &. * const限定的全局对象默认是static的,不会跨文件共享,正因此,若const对象可能被共享,也应当优先定义在头文件中. * const在与指针联用时,要注意限定的部分.规定:若限定指针自身为不可写,则将const写在*右侧;若是指向的对象不可写,则const写在*左侧. * 若const用于限定对象自身不可写

By Edimetia3D

C++系列

[Cpp基础] [04] 名字查找与函数重载

名字查找 * 当我们使用一个名字时,编译器就会向上查找名字的声明语句.变量名的查找和函数名的查找结果有一定区别. * 变量名查找:最终仅会确定唯一的对象,从内到外碰到的第一个名字将被使用. * 函数名查找:会先确定搜索域,然后按重载规则选择最有匹配. 搜索域包含一般scope和参数scope. * 常规搜索域确定:从当前作用域开始,逐层向上查找名字声明,名字首次出现的作用域就是常规搜索域 * 对于函数调用的每个实参arg_i,其类型decltype(arg_i)及其所有基类所在的作用域都加入实参类型搜索域 * 函数名和变量名都是名字,彼此可以相互hide. 重载匹配规则 * 函数重载的基础是传入参数的类型,和返回类型无关.对于非引用的形参,const不作为重载的依据. * 首先根据实参类型排除不能产生调用的函数,得到一个可行函数列表. 在可行列表中: 类型转换越少越好,在此前提下, 特化的优先于一般的. * 注意: * 仅函数/数组向指针的转换是精确匹配,只要类型不同,都被视作类型转换,例如:派生类指针到基类指针,非

By Edimetia3D

C++系列

[Cpp基础] [03] 变量声明-定义及初始化

变量的"声明,定义"以及"初始化" 想要彻底理解这一部分的内容,你应该对OS/进程/虚拟内存/编译/链接过程有一定的了解,仅从语言层次学习是比较抽象的. 声明和定义 * 从编译的角度看: * 仅声明某个变量,那么就只创建了Symbol,这个Symbol对应的存储空间需要在后续的链接过程中resolve. * 定义某个变量,在创建Symbol的同时,编译器为其分配了存储空间, 这个存储空间可以被链接器reslove道引用这个Symbol的地方. * 对开发者而言: * 如果你希望使用某个已经存在的对象,那么就应该使用声明语句. * 每个定义语句都有"声明"的效果,不存在只定义不声明的语句. * 就C++而言,若语句仅有extern,且不含任何初始化部分,则该语句就是一个纯粹的声明,例如 * extern T &val;//纯声明 * extern T val;//纯声明 * extern

By Edimetia3D

C++系列

[Cpp基础] [02] 拷贝/移动与引用

这一部分主要介绍左值,右值,引用,拷贝和移动.这些可以说是C++11显著区别于以前的C++(还有C)的特性.本文主要从易用的角度介绍值类型(值类型实际要更多一些). 拷贝与移动的基本定义 * "拷贝"和"移动"是从逻辑层面定义的,在最终的指令层面,只有"拷贝",没有"移动"操作. * 对于自定义类,拷贝与移动的实现有基本的准则(非硬性),这些准则是: * 拷贝:不应对源对象做任何修改. * 移动:可以对源对象做修改,但是源对象被修改后必须可以被赋值,且可以安全的析构. * 注意,对于移动操作.我们不能对移出后剩余的部分做任何假定,在没有重新赋值前,不应该使用移出后剩下的对象 * 例如:对一个vector<int> a;

By Edimetia3D

C++系列

[Cpp基础] [01] Cpp编译系统基础

编译系统基础 工具链 * 一个典型的工具链是:链接器-编译器(汇编器一般不接触)-预处理器-文本编辑器-构建系统 * 调试工具及profile工具通常作为独立的部分出现. * 构建系统,或者称为工程管理器,对于开发意义重大,是工具链中重要的一环,其意义在于组织文件,管理源代码,明确目标输出,组织编译/链接的顺序和关系. * 常见的构建系统有,VS的nmake,QT的qmake,跨平台的CMAKE(使用makelist.txt),unix平台的make(使用makefile).其中CMAKE是目前事实上的标准构建系统,bazel也随着google项目的扩张越来越流行 * VS和QT这样的IDE对自己的构建系统更加友好,往往可以按GUI的形式设置构建参数,CMAKE等则都需要开发者手动写构建文件. * 使用#ifndef 或者#pragma once可以有效的避免重复include,一个正常的头文件都应该包含include guard.

By Edimetia3D