10. 优化结构体中元素的布局

结构体变量所占空间大小并不是其所含类型所占字节数之和,其所占内存字节数涉及到字节对齐。

字节对齐 :变量在内存中储存都是以字节数为单位,每一个字节都有自己的地址,逻辑上变量的首地址(第一个字节的地址)可以是任意位置,但实际不同类型变量其首地址是有一定规则的,这是为了更快的查找便于存取(牺牲空间来换取效率)。

结构体变量中的各个类型在内存中存放时也按照一定的规则,并不是简简单单的用连续的内存 挨边存放。

其遵循的规则有:

(1)结构体变量的首地址可以被其所含最宽的基本类型的大小所整除。

(2)其结构体变量所含各个基本类型的首地址相对于结构体变量的首地址来说的偏移量应为自身大小的整数倍。(如有需要,编译器会在两个基本类型存储的中间填充字节以满足要求)

(3)其结构体变量总的宽度应为其所包含的最宽基本类型大小的整数倍。(如有所需,编译器会在其尾部填充字节以满足要求)

在编程中可以利用上述规则来合理的安排定义数据的顺序减少占用的空间(即减少填充的字节)

,也可以自己显式的填充字节(其实显式填充和编译器自动填充一样,这些填充的内存单元都对程序每有意义)------------空间换取时间

在编程中如果对时间效率要求不高,而空间资源紧张的话可以利用编译器的pack()指令显式的调整结构体的对齐方式。

#pragma pack{ n }     //n为字节数,其取值为1,2,4,8,16,默认是8

struct  A
{
int a;
char b;
short c;
};

如果不用编译器的pack()指令的话则sizeof(A)为8.

如果利用pack()指令并让n为1的话,其结构体对齐方式为1字节对齐,则sizeof(A)为7

-----------时间换取空间

11. 尽量少用强制类型转换

c++保留了C风格的强制类型转换,而且具有自己新风格的强制转换

(1)c风格的强制类型转换

形式为:

类型标识符(待转换变量)或(类型标识符)待转换变量

这种强制类型转换比较危险,其会产生一些难以发现的问题,例如

int a=65536;
int i=unsigned short(a);

i的值为0;

因为在32位的机器中int型的数据占4个字节范围为-2147483648~2147483647

而unsigned short类型的数据占2个字节范围为

0~65535

当把一个大于65535的int类型数据强制转换为unsigned short类型数据时发生内存截断(4个字节截取后两个字节)。相同如果把unsigned类型的数据转换为int类型则会发生内存扩张

(2)c++新式风格的强制类型转换

① const_cast<T*>(a)

其可以去除类中的const ,volatile,和__unaligned属性。

calss a
{
//code
};
int main()
{
const a *p1 =new a; //p1为一个指向常对象的指针变量
a *p2=p1; //错误,const指针不能赋值给非const指针
a *p3=const_cast<a*>(p1) //正确,

利用const_cast<T*>(a)对p1常指针进行强制类型转换去除其const属性,使其可以赋值给非const指针

②dynamic_cast<T*>(a)

其与c++的动态多态性有关。

c++中通过把基类函数设置为虚函数来实现动态多态性,即可以通过定义基类指针指向不同继承类对象来调用其相关方法,前提是这种继承类对象的相关方法得在基类中声明为虚函数,否则用基类指针无法直接调用。 这时候就需要获得这种继承类对象的类型,通过dynamic_cast<T*>(a)来强制转换其指针类型从而调用其特有方法

calss A
{
//code
};
class B:public A
{
//code
};
class C:public B
{
//code
};
int main()
{
A *p1=new C;
C *p2=dynamic_cast<C*>(p1); //正确,安全p2为C类型的指针
B *p3=dynamic_cast<B*>(p1); //错误,不安全p3为空指针
return 0;
}

通过p2指针就可以调用c类型特有的方法。

dynamic_cast<T*>(a)其是通过对类名称通过字符串比较来实现的,其在继承中所处的层次越深,其字符串比较的次数就越多(为了找到对应类名称),需要花费很大时间,不如不用直接定义对应类型的指针;

③reinterpret_cast<T*>(a)

它用于不同类类型指针之间的转换;

class A
{
.....
}
class B
{
......
}
int main()
{
A *p1=new A;
B *p2=reinterpret_cast<B*>(A);
return 0;
}

因为A与B是不同的两个类型,其具有不同的内存储存形式,强行对其转换可能会发生内存扩张或内存截断。

④static_cast<*T>(a)

**总结:**由上述可得在程序中使用强制类型转换会带来一系列安全问题,且不易发觉因此在程序中尽量少使用强制类型转换。

改善c++程序的150个建议(读后总结)-------10-11的更多相关文章

  1. 编写高质量代码_改善C++程序的150个建议 读书笔记

    这几天看了下这本书<编写高质量代码_改善C++程序的150个建议>,觉的蛮有收获的,再次记录下自己以前不清晰的知识点,以供学习. 编写符合标准的main函数 C语言标准规定了main函数的 ...

  2. 改善c++程序的150个建议(读后总结)-------19-26

    19. 明白在c++中如何使用c c++可以兼容c的绝大部分代码,但是还是有一部分不能兼容. c语言的编译器在调用函数时会把函数翻译成 : "_函数名",例如: int nasa( ...

  3. 改善c++程序的150个建议(读后总结)-------12-18

    12.优先使用前置操作符 #include <iostream> using namespace std; class A { private: int num; public: A op ...

  4. 改善c++程序的150个建议(读后总结)-------0-9

    0. 不要让main 函数返回 void 入口函数main()返回类型应该为 int, 即程序结束时return 0 表示程序正常返回,函数结束时 return -1 值表示程序异常返回, 如果不显式 ...

  5. 改善c++程序的150个建议(读后总结)-------27-35

    27. 区分内存分配的方式 c++中内存分为5个不同的区 ①栈区 栈是一种特殊的数据结构,其存取数据特点为(先进后出,后进先出).栈区中主要用于存储一些函数的入口地址,函数调用时的实参值以及局部变量. ...

  6. 改善C++ 程序的150个建议学习之建议7:时刻提防内存溢出

    作为一个程序员,对内存溢出问题肯定不陌生,它已经是软件开发历史上存在了近40年的大难题.在内存空间中,当要表示的数据超出了计算机为该数据分配的空 间范围时,就产生了溢出,而溢出的多余数据则可以作为指令 ...

  7. 编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法、Lambda表达式代替方法

    建议150:使用匿名方法.Lambda表达式代替方法 方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐.比如: static void SampeMethod() { List< ...

  8. 改善java程序的151个建议

    <编写高质量代码-改善java程序的151个建议> --秦小波 第一章.开发中通用的方法和准则 1.不要在常量和变量中出现易混淆的字母 long a=0l; --> long a=0 ...

  9. 编写高质量代码改善java程序的151个建议——导航开篇

    2014-05-16 09:08 by Jeff Li 前言 系列文章:[传送门] 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,慘不忍睹是吧.确实 ...

随机推荐

  1. css行高

    1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...

  2. Redis实战篇(三)基于HyperLogLog实现UV统计功能

    如果现在要开发一个功能: 统计APP或网页的一个页面,每天有多少用户点击进入的次数.同一个用户的反复点击进入记为 1 次,也就是统计 UV 数据. 让你来开发这个统计模块,你会如何实现? 如果统计 P ...

  3. 在Windows下配置Linux远程开发环境

    在Windows下配置Linux远程开发环境 欢迎光临我的个人博客 https://source.chens.life/Configure-Linux-remote-development-envir ...

  4. [LeetCode]2. 两数相加(难度:中等)

    题目: 给你两个非空的链表,表示两个非负的整数.它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字.请你将两个数相加,并以相同形式返回一个表示和的链表.你可以假设除了数字0之外,这两个 ...

  5. k8s:py项目发布完整流程

    k8s:py项目发布流程 1. 编写Dockerfile # cat Dockerfile FROM python:3.6-slim USER root RUN apt-get update & ...

  6. 干货!Apache Hudi如何智能处理小文件问题

    1. 引入 Apache Hudi是一个流行的开源的数据湖框架,Hudi提供的一个非常重要的特性是自动管理文件大小,而不用用户干预.大量的小文件将会导致很差的查询分析性能,因为查询引擎执行查询时需要进 ...

  7. “改造” VS Code 编辑器,一起写个插件吧!

    作者:HelloGitHub-小夏(首发于 HelloGitHub 公众号) 作为一个靠代码作为"生计"的开发者,bug 写的好不好,编辑器真的很重要!那么 Visual Stud ...

  8. Linux下禁用笔记本触摸板

    1 概述 在Linux下禁用触摸板的方法有很多,这里列举三种: 图形界面配置关闭 modprobe关闭 xinput关闭 2 图形界面配置关闭 笔者的环境为Manjaro+Xfce,其他的桌面也应该类 ...

  9. ECDSA密钥对生成以及在Token中的应用

    1 概述 本文主要讲述了如何利用Openssl生成ECDSA密钥对,并利用Auth0库进行Token生成及验证的过程. 2 ECDSA 2.1 简介 ECC(Elliptic Curve Crypto ...

  10. 基于MATLAB的手写公式识别(5)

    基于MATLAB的手写公式识别 总结一下昨天一天的工作成果: 获得了大致的识别过程. 一个图像从生肉到可以被处理需要经过预处理(灰质化.增加对比度.中值过滤.膨胀或腐蚀.闭环运算). 掌握了相关函数的 ...