如何平衡性能,合理选择C++STL集装箱?

ANSER:

首先要搞清楚,假设STL问题,那么问题出在哪里?

STL能够简单地觉得就是算法+数据结构,全部容器的算法选择和实现都是经过精心设计和严格測试的,几个主流STL实现都不会有大问题。

性能问题通常都出在内存数据操作上,内存操作有三种。内存读取、内存复制和内存分配。

所以选择合适容器的根据就是要尽量降低内存操作尤其是复制操作,比方频繁中间插入删除就不要选Vector,频繁随机訪问就不要选list。

除了选错容器这种低级错误外,性能瓶颈基本都是出在容器内的对象身上。解决方式:

  1. 在容器内放对象指针,而不是实例,对象生命周期自己管理,仅仅有在真的有性能问题时才考虑这样做,由于内存泄漏的风险还是挺高的。
  2. 自定义allocator,实现对象内存池,仅仅有在确认内存分配是瓶颈时才用。
  3. 不拿两个容器实例做赋值操作,传入參数用指针或引用,传出的參数用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++问题整理的更多相关文章

  1. 《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 ...

  2. 三年从前端小工到架构-知乎 Live 学习整理

    最近在知乎上学习了vczero (王利华,簋谣)的知乎Live「三年从前端小工到架构」,感觉受益匪浅,现将本次Live学习笔记记录如下. 本次 Live 主要包括以下内容   • 0-3 年的前端工程 ...

  3. 八皇后算法的另一种实现(c#版本)

    八皇后: 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于 ...

  4. [Android Tips] 19. Android Studio Plugins

    Code Generation GsonFormat json 字符串生成实体类 https://github.com/zzz40500/GsonFormat Android Parcelable C ...

  5. 我的Linux随笔目录

    现在整理博客的时间少了,大多是在用为知笔记收藏和整理,一次集中发点Linux相关随笔整理和一个目录,是按时间顺序来的.每一篇都是自己用过之后整理的,应用场景已经尽可能的说明了,不明白的可以Q我,上班时 ...

  6. 机器学习--kNN算法识别手写字母

    本文主要是用kNN算法对字母图片进行特征提取,分类识别.内容如下: kNN算法及相关Python模块介绍 对字母图片进行特征提取 kNN算法实现 kNN算法分析 一.kNN算法介绍 K近邻(kNN,k ...

  7. Beta冲刺 总结

    Beta冲刺 总结 1. 完成情况 经过了为其七天的beta冲刺,我们基本完成了之前在<beta开始前准备>博客中所列出的内容. 增加关于征信的功能,贴近选题主题.在学生的信用活动记录中添 ...

  8. 射线和三角形的相交检测(ray triangle intersection test)【转】

    本文以Fast, Minimum Storage Ray Triangle Intersection为参考,在此感谢原作者,大家也可以直接阅读原版. 概述 射线和三角形的相交检测是游戏程序设计中一个常 ...

  9. Python爬虫开源项目代码,爬取微信、淘宝、豆瓣、知乎、新浪微博、QQ、去哪网等 代码整理

    作者:SFLYQ 今天为大家整理了32个Python爬虫项目.整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心.所有链接指向GitHub,祝大家玩的愉快 1.WechatSogou [ ...

随机推荐

  1. 神奇校车 = topsage

    https://post.smzdm.com/p/6356/ 适合6岁至99岁的小盆友看的<The Magic School Bus> (神奇校车) http://club.topsage ...

  2. css3-8 内外边距中的注意要点有哪些

    css3-8 内外边距中的注意要点有哪些 一.总结 一句话总结:padding,border都是外延的.margin会合并. 1.两元素样式都有margin:15px,他们中间的距离是15px还是30 ...

  3. Python 标准库和第三方库的安装位置、Python 第三方库安装的各种问题及解决

    首先使用 sys 下的 path 变量查看所有的 python 路径: import sys sys.path 标准库 lib 目录下(home 目录/pythonXX.XX/lib) 第三方库 在 ...

  4. IIS服务器能支持10万并发

    服务器能支持10万并发由于一个项目的访问量越来越大,从原来的几百个,增加到现在50多万个每天,所以阿里的服务器也扛不住了,于是就想办法,查了N多资料,总结了以下方法,才解决这问题,每天一共访问量50多 ...

  5. Android CursorAdapter的使用详解

    一.CursorAdapter介绍 CursorAdapter这个类是继承于BaseAdapter的它是一个虚类它为Cursor和ListView连接提供了桥梁 二.CursorAdapter详解 1 ...

  6. 断言(Assert)与异常(Exception)

    ## 断言和异常 断言是用来检查非法情况而不是错误情况的,用来帮开发者快速定位问题的位置. 异常处理用于对程序发生异常情况的处理,增强程序的健壮性和容错性. ## 断言的使用 在防御式编程中经常会用断 ...

  7. [Ramda] Refactor to Point Free Functions with Ramda using compose and converge

    In this lesson we'll take some existing code and refactor it using some functions from the Ramda lib ...

  8. iOS 直播

    待解决: 貌似苹果规定10M以内的视频可以用RTMP,以上的必须用HLS  ? IOS非直播超过10分钟只能用hls,ios上有规定? 待尝试: 用Vitamion内核开发的可以自定义界面的视频播放器 ...

  9. MapKit

    MapKit MapKit框架的使用 nMapKit框架使用前提 p导入框架 p p导入主头文件 #import <MapKit/MapKit.h> MapKit框架使用须知 pMapKi ...

  10. [redis] redis配置文件redis.conf的详细说明

    # Redis 配置文件 # 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写) # # 1k => bytes # 1kb => ...