知乎C++问题整理
如何平衡性能,合理选择C++STL集装箱?
ANSER:
首先要搞清楚,假设STL
问题,那么问题出在哪里?
STL
能够简单地觉得就是算法+数据结构,全部容器的算法选择和实现都是经过精心设计和严格測试的,几个主流STL
实现都不会有大问题。
性能问题通常都出在内存数据操作上,内存操作有三种。内存读取、内存复制和内存分配。
所以选择合适容器的根据就是要尽量降低内存操作尤其是复制操作,比方频繁中间插入删除就不要选Vector
,频繁随机訪问就不要选list
。
除了选错容器这种低级错误外,性能瓶颈基本都是出在容器内的对象身上。解决方式:
- 在容器内放对象指针,而不是实例,对象生命周期自己管理,仅仅有在真的有性能问题时才考虑这样做,由于内存泄漏的风险还是挺高的。
- 自定义
allocator
,实现对象内存池,仅仅有在确认内存分配是瓶颈时才用。 - 不拿两个容器实例做赋值操作,传入參数用指针或引用,传出的參数用
swap
来实现容器数据传递,务必确认自己清楚知道在做什么。
关于C++ 数组和指针的问题?
对数组取地址时。数组名不会被解释为其地址。等等。数组名难道不被解释为数组的地址吗?不全然如此:数组名被解释为其第一个元素的地址,而对数组名应用地址运算符(即&)时,得到的是整个数组的地址:
short tell[10]; //声明一个长度为20字节的数组(short型变量大小为2字节)
cout << tell << endl; //显示&tell[0]
cout << &tell << endl; //显示整个数组的地址
从数字上说,这两个地址同样;但从概念上说,&tell[0]
(即tell
)是一个2字节内存块的地址,而&tell
是一个20字节内存块的地址。
因此。表达式tell+1
将地址值加2。而表达式&tell+1
将地址值加20。换句话说。tell
是一个short
指针(short*
),而&tell
是一个指向包括10个元素的short
数组的指针(short(*) [10])
。
您可能会问,前面有关&tell
的类型描写叙述是怎样来的呢?
首先,您能够这样声明和初始化这种指针:
short (*pas) [10] = &tell; //pas指向一个有10个short元素的数组
假设省略括号,优先级规则将使pas
先与[10]
结合。导致pas
是一个包括10个short
型指针的数组。因此括号是不可缺少的。
其次,假设要描写叙述变量的类型。可将声明中的变量名删除。因此。pas
的类型为short(*) [10]
。
另外。由于pas
被设置为tell
。因此*pas
与tell
等价,所以(*pas) [0]
为tell
数组的第一个元素。
回到问题本身,当int
型变量的大小为4字节时,arr
是一个4字节内存块的地址,而&arr
是一个40字节内存块的地址。
尽管这两个内存块的起始位置同样,可是大小不同。
题主能够在代码里加上这两行,对照一下输出结果:
cout << arr + 1 << endl; //地址+4
cout << &arr + 1 << endl; //地址+40
演示样例代码:
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
cout << &(arr[0]) << endl;
cout << arr << endl;
cout << &arr << endl;
cout << arr + 1 << endl;
cout << &arr + 1 << endl;
输出:
0013FE60
0013FE60
0013FE60
0013FE64
0013FE88
请按随意键继续. . .
C/C++ 中 0 与 NULL 差别是什么?用 delete 时,用 p=0,还是用 p=NULL 好?为什么?
ANSER:
首先呢。要明确一点儿。NULL
是一个无类型的东西,并且是一个宏。而宏这个东西,从C++
诞生開始。就是C++
之父嗤之以鼻的东西,他推崇尽量避免宏。而在他的FAQ
中,也有对应的一个关于NULL
与0
的解释。也谈到了这一点儿。
在C++
标准中。我们能够见到一个词语叫做null pointer constant
,事实上在C++11
标准前。是仅仅承认0
为null pointer constant
的。所以,在C++
中,我们也常常能听到一个说法,就是赋予null pointer
。应该是使用0
,而非NULL
。
而nullptr pointer constant
这个词语在C++11
公布后,最终再添了一个成员,就是nullptr
。而与NULL
本质不同的是,nullptr
是有类型的(放了在stddef
头文件里),类型是 typdef decltype(nullptr) nullptr_t
; 而正是由于是有类型的,这给我们编译器实现nullptr
的时候带来了很多其它细节的考虑,当然也给了使用者很多其它的保障,所以假设你的编译器支持nullptr
,请一定使用nullptr
!
而nullptr
的出现背景,事实上是很easy的,C++
哲学上来说就是C++
之父一直对null pointer
没有一个正式的表示感到很不满。而更project的来说,就是关于重载这个问题。
void f(void*)
{
}
void f(int)
{
}
int main()
{
f(0); // what function will be called?
}
而引入了nullptr
。这个问题就得到了真正解决,会很顺利的调到void f(void*)
这个版本号。
好了。真的以为nullptr
就这样了么? 我前面说过了nullptr
是有类型的,叫做nullptr_t
,这给我们编译器实现带来了诸多要考虑的东西。不幸的话让我们来举点儿奇葩样例吧。
union U
{
long i;
nullptr_t t;
};
int main()
{
U u;
u.i = 3;
printf("%ld\n",(long)u.t); // What it is? 0 or 3?
}
那么这是应该符合union
语意还是nullptr
的语意呢?这在标准中是没有说的,我们也为此争论了很久。
当然在我们编译器的实现还是保持了nullptr
的语意,结果是0
。
而nullptr
有类型后。还能做什么呢?那当然就是能够捕获异常了。
int main()
{
try
{
throw nullptr;
}
catch(nullptr_t)
{
}
}
你扔一个NULL
试试?看他应该用什么收,正是由于没有类型,所以就要用它的本质类型。比方long
什么的来说。你扔一个0试试?那就也不是所谓的空指针类型了,就是要用int
什么的来收了。
所以,推崇nullptr
是有道理的,我们在编译器实现nullptr
的时候考虑了很很多的细节。还有很多你们可能一直用不到的情况,我们都要用来測试。目的就是保障开发人员的使用。再次那句话。假设你的编译器支持nullptr
,请一定使用nullptr
!
最后再扯一点儿,0
在C++
是很奇妙的东西。比方纯虚函数为什么是用=0
来设置的,不知道有没有同学去考虑过这个问题没有。
假设你深刻理解了C++
哲学,这应该就是很简答的问题了。学语言嘛,一定要学到其哲学,你才干知道其之美。其之威力。尤其是C++
。
怎样计算带指针的结构体大小?
问题:
struct X
{
char a;
float b;
int c;
double d;
unsigned e;
};
由于存储变量时地址对齐的要求,所以这个结构体大小应该是32。
假设我多定义一个随意型的指针
struct X
{
char a;
float b;
int c;
double d;
unsigned e;
int *f;
};
依照地址对齐的要求。这样结构体大小应该是40,但它仍然是32。
我再加一个随意型的指针
struct X
{
char a;
float b;
int c;
double d;
unsigned e;
int *f;
double *g;
};
结果这样结构体大小就直接变成40了。假设指针大小是地址总线大小的话,2个指针就是8字节,加上原来的32字节也刚好等于40字节,并且也满足存储变量时地址对齐的要求。
可是为什么刚才加一个指针不变。两个就变了。
回答:
一開始的时候是这种
struct X {
char a; // 1 bytes
char padding1[3]; // 3 bytes
float b; // 4 bytes
int c; // 4 bytes
char padding2[4]; // 4 bytes
double d; // 8 bytes
unsigned e; // 4 bytes
char padding3[4]; // 4 bytes
};
加了一个指针以后是这种
struct X {
char a; // 1 bytes
char padding1[3]; // 3 bytes
float b; // 4 bytes
int c; // 4 bytes
char padding2[4]; // 4 bytes
double d; // 8 bytes
unsigned e; // 4 bytes
int *f; // 4 bytes
};
再加一个指针以后是这种
struct X {
char a; // 1 bytes
char padding1[3]; // 3 bytes
float b; // 4 bytes
int c; // 4 bytes
char padding2[4]; // 4 bytes
double d; // 8 bytes
unsigned e; // 4 bytes
int *f; // 4 bytes
double *g; // 4 bytes
char padding3[4]; // 4 bytes
};
这样就好懂多了吧?
轮子哥的回答。说明了原理
我来补充一下匿名用户的答案。
第一个图是这种
struct X {
char a; // 1 bytes
char padding1[3]; // 3 bytes
float b; // 4 bytes
int c; // 4 bytes
char padding2[4]; // 4 bytes
double d; // 8 bytes
unsigned e; // 4 bytes
char padding3[4]; // 4 bytes
};
padding1
的存在是由于,offset(b)
必须能够被align(b)
整除,所以塞三个char
。
b
的偏移字节是它自身字节的整数倍,因此要加入三个字节的偏移
padding2
的存在是由于,offset(d)
必须能够被align(d)
整除,所以塞4个char
。
原因同上
对于全部基本类型,align(T)==sizeof(T)
,所以有了上面两条。
那align(X)
是多少呢?当然就是全部成员里面align
最大的那个,是align(d)==8
好了,因此sizeof(X)
必须能够被align(X)
整除,就有了padding3
。
整个结构体的大小必须能被当中最大
align
的树整除。
知乎C++问题整理的更多相关文章
- 《MySQL必知必会》整理
目录 第1章 了解数据库 1.1 数据库基础 1.1.1 什么是数据库 1.1.2 表 1.1.3 列和数据类型 1.1.4 行 1.1.5 主键 1.2 什么是SQL 第2章 MySQL简介 2.1 ...
- 三年从前端小工到架构-知乎 Live 学习整理
最近在知乎上学习了vczero (王利华,簋谣)的知乎Live「三年从前端小工到架构」,感觉受益匪浅,现将本次Live学习笔记记录如下. 本次 Live 主要包括以下内容 • 0-3 年的前端工程 ...
- 八皇后算法的另一种实现(c#版本)
八皇后: 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于 ...
- [Android Tips] 19. Android Studio Plugins
Code Generation GsonFormat json 字符串生成实体类 https://github.com/zzz40500/GsonFormat Android Parcelable C ...
- 我的Linux随笔目录
现在整理博客的时间少了,大多是在用为知笔记收藏和整理,一次集中发点Linux相关随笔整理和一个目录,是按时间顺序来的.每一篇都是自己用过之后整理的,应用场景已经尽可能的说明了,不明白的可以Q我,上班时 ...
- 机器学习--kNN算法识别手写字母
本文主要是用kNN算法对字母图片进行特征提取,分类识别.内容如下: kNN算法及相关Python模块介绍 对字母图片进行特征提取 kNN算法实现 kNN算法分析 一.kNN算法介绍 K近邻(kNN,k ...
- Beta冲刺 总结
Beta冲刺 总结 1. 完成情况 经过了为其七天的beta冲刺,我们基本完成了之前在<beta开始前准备>博客中所列出的内容. 增加关于征信的功能,贴近选题主题.在学生的信用活动记录中添 ...
- 射线和三角形的相交检测(ray triangle intersection test)【转】
本文以Fast, Minimum Storage Ray Triangle Intersection为参考,在此感谢原作者,大家也可以直接阅读原版. 概述 射线和三角形的相交检测是游戏程序设计中一个常 ...
- Python爬虫开源项目代码,爬取微信、淘宝、豆瓣、知乎、新浪微博、QQ、去哪网等 代码整理
作者:SFLYQ 今天为大家整理了32个Python爬虫项目.整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心.所有链接指向GitHub,祝大家玩的愉快 1.WechatSogou [ ...
随机推荐
- 是男人就下100层【第四层】——Crazy贪吃蛇(3)
上一篇<是男人就下100层[第四层]--Crazy贪吃蛇(2)>实现了贪吃蛇绕着屏幕四周移动,这一篇我们来完成贪吃蛇的所有功能. 一.随机产生苹果 private void addAppl ...
- “locktype”enum type 类型重定义问题的解决
作者:朱金灿 来源:http://blog.csdn.net/clever101 使用ado来连接数据库,结果出现这样一些编译错误: 1>f:\c++pro\iocptser\debug\msa ...
- ZOJ 1203 Swordfish MST
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1203 大意: 给出一些点,求MST 把这几天的MST一口气发上来. kru ...
- Vue源码--深入模板渲染
原文链接:https://geniuspeng.github.io/2018/02/07/vue-compile/ 之前整理了vue的响应式原理,在这里有一点是一直很模糊的,就是何时去new一个wat ...
- Lucene学习总结之八:Lucene的查询语法,JavaCC及QueryParser 2014-06-25 14:25 722人阅读 评论(1) 收藏
一.Lucene的查询语法 Lucene所支持的查询语法可见http://lucene.apache.org/java/3_0_1/queryparsersyntax.html (1) 语法关键字 + ...
- 【Lucene4.8教程之三】搜索 2014-06-21 09:53 1532人阅读 评论(0) 收藏
1.关键类 Lucene的搜索过程中涉及的主要类有以下几个: (1)IndexSearcher:执行search()方法的类 (2)IndexReader:对索引文件进行读操作,并为IndexSear ...
- 益智小游戏(app)
最好的益智类游戏要基于一定的数学原理. 一笔完成:(拓扑学,哥尼斯堡问题) 哥尼斯堡七桥问题
- TF-IDF计算方法和基于图迭代的TextRank
文本处理方法概述 说明:本篇以实践为主,理论部分会尽量给出参考链接 摘要: 1.分词 2.关键词提取 3.主题模型(LDA/TWE) 4.词的两种表现形式(词袋模型和分布式词向量) 5.关于文本的特征 ...
- OpenGL核心之视差映射
笔者介绍:姜雪伟,IT公司技术合伙人.IT高级讲师,CSDN社区专家,特邀编辑.畅销书作者;已出版书籍:<手把手教你¯的纹理坐标偏移T3来对fragment的纹理坐标进行位移.你能够看到随着深度 ...
- ios 第一篇文章-xcode6.2键盘调不出来
ios 第一篇文章 不晓得有没有人遇到过ios代码内调用键盘(keyboard)调不出来的情况,反正我是遇到了,按官方文档的说法调用键盘事件非常easy事实上: 我用了之后,不晓得为嘛,键盘就是不显示 ...