auto是c++程序设计语言的关键字。用于两种情况
(1)声明变量时根据初始化表达式自动推断该变量的类型
(2)声明函数时函数返回值的占位符
static_cast:
《C++四种类型转换运算符:static_cast、dynamic_cast、const_cast和reinterpret_cast》
http://c.biancheng.net/cpp/biancheng/view/3297.html
static_cast 显式类型转换,static_cast 是“静态转换”的意思,也就是在编译期间转换,转换失败的话会抛出一个编译错误。
xxx_cast(data)
老式C风格:
double scores = 95.5;
int n = (int)scores;
C++新风格:
double scores = 95.5;
int n = static_castint>(scores);
C风格的强制类型转换统一使用( ),而( )在代码中随处可见,所以也不利于使用文本检索工具(例如 Windows 下的 Ctrl+F、Linux 下的 grep 命令、Mac 下的 Command+F)定位关键代码。为了使潜在风险更加细化,使问题追溯更加方便,使书写格式更加规范,C++ 对类型转换进行了分类,并新增了四个关键字来予以支持static_cast、dynamic_cast、const_cast和reinterpret_cast。
#if defined #ifdef 区别
注意两者都有个define的作用,区别在于使用方式上。前者的通常用法是:
#ifdef XXX
...
#else
...
#endif
#ifdef 只能在两者中选择是否有定义。对于后者,常用法是:
#if defined xxx1
....
#elif defined xxx2
....
#elif defined xxx3
....
#endif
可以在多个中选择是否有定义.
#ifdef是#if defined的功能简化版,只是判断单个宏是否被定义时可用#ifdef,其它复杂条件都得用#if defined。
_MSC_VER
_MSC_VER 是MSVC编译器的内置宏,定义了编译器的版本。在程序中加入_MSC_VER宏可以根据编译器版本让编译器
有选择性地编译一段程序。
MS Microsoft 的简写。
C MSC 就是 Microsoft 的 C 编译器。
VER Version 的简写。
因此_MSC_VER的意思就是:Microsoft 的 C 编译器的版本。
Linux和Windows是两大编程平台,这两个系统的C++程序不一定能够兼容,在linux平台下能够运行的程序不一定
能在windows下运行,在windows平台下的C++程序不一定能在Linux下运行,因此如果希望写出来的程序对于两个
平台兼容,那么就需要在写代码的时候进行手动控制。
__declspec(dllexport)
__declspec是Microsoft VC中专用的关键字,它配合着一些属性可以对标准C/C++进行扩充。__declspec关键字应
该出现在声明的前面。
__declspec(dllexport) 用于Windows中的动态库中,声明导出函数、类、对象等供外面调
用,省略给出.def文件。即将函数、类等声明为导出函数,供其它程序调用,作为动态库的对外接口函数、类等
。如果不提供 __declspec(dllexport) 导出DLL函数,则DLL需要提供.def文件。
std::shared_ptr
问题来源: mnn/demo/exec 里 multiPose.cpp 的 main() 函数里:
// create net and session
auto mnnNet = std::shared_ptr(MNN::Interpreter::createFromFile(poseModel));
C++智能指针,
《C++11 shared_ptr智能指针(超级详细)》: C++11 shared_ptr智能指针(超级详细) - C语言中文网 ,
《智能指针shared_ptr的用法》 https://www.cnblogs.com/jiayayao/p/6128877.html ,
C++有 shared_ptr、unique_ptr、weak_ptr 这 3 个智能指针。
要使用 shared_ptr 需:
#include
using namespace std;
shared_ptr 类模板中(其中 T 表示指针指向的具体数据类型),提供了多种实用的构造函数
std::vector
vector : C++ 容器,
class Backend : public NonCopyable {
NonCopyable : 不可拷贝类
《boost学习之noncopyable》: https://blog.youkuaiyun.com/s_lisheng/article/details/72888575
std::mutex
问题来源: std::mutex lock;
https://www.cnblogs.com/haippy/p/3237213.html,
Mutex 又称互斥量,C++ 11中与 Mutex 相关的类(包括锁类型)和函数都声明在 头文件中,
std::mutex,最基本的 Mutex 类,
问题来源: return createMultiPathSession(configs, std::move(runtime));
Session* Interpreter::createMultiPathSession(const std::vector& configs, const RuntimeInfo& runtime) {
std::move 是啥?
https://blog.youkuaiyun.com/p942005405/article/details/84644069
在C++11中,标准库在中提供了一个有用的函数std::move,std::move并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast(lvalue);
问题来源: Tensor* Session::getInput(const char* name) const {
方法(函数)后接 const 何意?
https://blog.youkuaiyun.com/whahu1989/article/details/80501685
https://www.runoob.com/w3cnote/cpp-construct-function-initial-list.html
声明一个成员函数的时候用const关键字是用来说明这个函数是 “只读(read-only)”函数,也就是说明这个函数不会修改任何数据成员(object)。
为了声明一个const成员函数, 把const关键字放在函数括号的后面。
声明和定义的时候都应该放const关键字。
任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误,这无疑会提高程序的健壮性.
函数(方法)后接 "const=0" 合意?
const 和 =0 没有关系,要分开理解。
成员函数后面用 const 修饰,通俗的理解就是在这个函数内不能修改类的成员变量,除非那个成员变量是 mutable 的。
"=0" 表示这个成员函数是纯虚函数,也就是它可以没有定义,只有接口,由它的继承类具体定义它的行为,当然,你也可以给它定义缺省的函数体。
一个类里如果包含 =0 的纯虚函数,那么这个类就是一个抽象类,它不能具体实例化(不能创建它的对象),而只能由它去派生子类。
C++ STL
《STL教程:C++ STL快速入门(非常详细)》 : http://c.biancheng.net/stl/
STL 是“Standard Template Library”的缩写,中文译为“标准模板库”。STL 是 C++ 标准库的一部分,不用 单独安装。
std::map
《C++中的STL中map用法详解》
https://www.cnblogs.com/fnlingnzb-learner/p/5833051.html,
map是容器的一种。
问题来源:
CastWrapExecution::CastWrapExecution(const CPUBackend::Creator* creator, const Op* op, Backend* backend,
const std::vector &inputs, const std::vector &outputs, halide_type_t runT)
: Execution(backend), runType(runT), mCreator(creator), mType(op->type()), mInputs(inputs) {
函数形参列表后的内容是啥?
如下代码中bookNo(s), unit_sold(n), revenue(p * n)这一部分,
这是构造函数初始值列表。
作用:为新创建的对象的数据成员赋初值。
构造函数初值是成员名字的一个列表,括号内的是初始值
如果初始值列表中没有给出全部成员的初始值,那么没有给值的成员就会按照默认的构造函数的形式来初始化
Sales_data(const string &s, unsigned &n, double p) :
bookNo(s), unit_sold(n), revenue(p * n){
...
}
MultiByteToWideChar()函数:
问题来源:
wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(CP_ACP, 0, file, -1, wFilename, sizeof(wFilename))) {
mFile = nullptr;
return;
}
解析:
MultiByteToWideChar()函数完成 "多字节字符" 到 "宽字符" 的转换。
《多字节字符与宽字符》: https://www.cnblogs.com/drfxiaoliuzi/p/7991337.html,
多字节字符:
char ch[] = "abc赵钱孙123";
那么你解析的时候,最好能对每个字符做一个标识:第一个字符a占用1个字节,第二个字符b占用1个字节第三个字符c占用1个字节第四个字符赵,占用2个字节第五个字符钱,占用2个字节第六个字符孙,占用2个字节第七个字符1,占用1个字节...
这样下来,如果存储一个带有中英文的字符,会比较麻烦,因为,你需要额外的一个数组,来表示上面的字符数组的每个元素,所占用的字节,这样才能正常解析。如此一来,简直太麻烦了。
宽字符:
比如,’赵‘这个字,用2个字节来表示,同样,‘A’也用两个字节来表示,这样虽然浪费了一部分内存空间(因为原来一个字节能表示的字符,现在都需要两个字节),但是,解析的时候会方便多了。
在C/C++中,宽字符类型wchar_t 它和我们熟悉的char类型是一样的,只不过,涉及宽字符的相关库函数,都要用宽字符类型的库函数来处理,一般有w作为前缀。名字和我们熟悉的差别并不大。比如库函数strlen()对应的是wcslen()。
宽字符并不一定是Unicode,Unicode只是宽字符编码的一种实现。它有三种常见的编码方式:UTF-8(1个字节表示)、UTF-16(2个字节表示)、UTF-32(4个字节表示)。
《MultiByteToWideChar和WideCharToMultiByte用法详解》
https://www.cnblogs.com/ranjiewen/p/5770639.html,
返回值:
如果函数运行成功,并且cchMultiByte不为零,返回值是由 lpMultiByteStr指向的缓冲区中写入的字节数;
如果函数运行成功,并且cchMultiByte为零,返回值是接收到待转换字符串的缓冲区所必需的字节数。(此种情况用来获取转换所需Char的个数)
如果函数运行失败,返回值为零。
std::pair, push_back, make_pair,
问题来源:
std::vector> mBlocks;
mBlocks.push_back(std::make_pair(size, block)); 《C++ pair的基本用法总结(整理)》 : https://blog.youkuaiyun.com/sevenjoin/article/details/81937695,
pair是将2个数据组合成一组数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存。另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair。 pair的实现是一个结构体,主要的两个成员变量是first和second,因为是使用struct不是class,所以可以直接使用pair的成员变量。
其标准库类型--pair类型定义在#include 头文件中,定义如下:
类模板:template struct pair
参数:T1是第一个值的数据类型,T2是第二个值的数据类型。
功能:pair将一对值(T1和T2)组合成一个值,这一对值可以具有不同的数据类型(T1和T2),两个值可以分别用pair的两个公有函数first和second访问。
pair p1; //创建一个空的pair对象(使用默认构造),它的两个元素分别是T1和T2类型,采用值初始化。
pair p1(v1, v2); //创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,second成员初始化为v2。
make_pair(v1, v2); // 以v1和v2的值创建一个新的pair对象,其元素类型分别是v1和v2的类型。
p1 < p2; // 两个pair对象间的小于运算,其定义遵循字典次序:如 p1.first < p2.first 或者 !(p2.first < p1.first) && (p1.second < p2.second) 则返回true。
p1 == p2; // 如果两个对象的first和second依次相等,则这两个对象相等;该运算使用元素的==操作符。
p1.first; // 返回对象p1中名为first的公有数据成员
p1.second; // 返回对象p1中名为second的公有数据成员
push_back:
Adds a new element at the end of the vector, after its current last element. The content of val is copied (or moved) to the new element。
flatbuffers:
问题来源:
MNN load完 xxx.mnn 数据后用 flatbuffers 第三方来验证数据。这个 flatbuffers 到底是个啥?
flatbuffers::Verifier verify((const uint8_t*)(net->buffer.get()), net->buffer.size());
if (false == VerifyNetBuffer(verify)) {
MNN_PRINT("Invalidate buffer to create interpreter\n");
delete net;
return nullptr;
}
先理解啥是序列化:
《序列化理解起来很简单》:https://zhuanlan.zhihu.com/p/40462507,
《序列化和反序列化》:https://tech.meituan.com/2015/02/26/serialization-vs-deserialization.html,
- 序列化: 将数据结构或对象转换成二进制串的过程
- 反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
序列化:把对象转化为可传输的字节序列过程称为序列化。
反序列化:把字节序列还原为对象的过程称为反序列化。
其实序列化最终的目的是为了对象可以跨平台存储,和进行网络传输。而我们进行跨平台存储和网络传输的方式就是IO,而我们的IO支持的数据格式就是字节数组。
因为我们单方面的只把对象转成字节数组还不行,因为没有规则的字节数组我们是没办法把对象的本来面目还原回来的,所以我们必须在把对象转成字节数组的时候就制定一种规则(序列化),那么我们从IO流里面读出数据的时候再以这种规则把对象还原回来(反序列化)。
如果我们要把一栋房子从一个地方运输到另一个地方去,序列化就是我把房子拆成一个个的砖块放到车子里,然后留下一张房子原来结构的图纸,反序列化就是我们把房子运输到了目的地以后,根据图纸把一块块砖头还原成房子原来面目的过程。
《深入浅出FlatBuffers原理》: https://zhuanlan.zhihu.com/p/391109273,
FlatBuffers 是一个开源的、跨平台的、高效的、提供了多种语言接口的序列化工具库。实现了与 Protocal Buffers 类似的序列化格式。由 Google 开源,现在它具有 C ++、C#、C、Go、Java、PHP、Python 和 JavaScript 的接口。
所以 .mnn 文件是按照一定协议构成的一系列二进制文件,并非直接的模型数据内容,是有协议数据在里面的,是可以被verify验证的。