new int[20]和new int[20]()
有()初始化为该类型的默认值 没有(为随机值) 开辟单个元素可以在()内随意初始化,但开辟数组是()内不能写入数字
类的成员方法在类体内定义和在类外定义:
1.类外定义的成员方法,在方法名字前面加类类型的作用域
2.类外定义的在调用时,有函数的正常开销(函数运行需要再栈上开辟内存);在类体内定义的函数,都被自动处理成inline内联函数(没有调用开销)
内存扩容(浅拷贝和深拷贝):
对于内置类型(指的就是int等),扩容时,可以直接使用memcpy&realloc等内存操作函数;
但是如果是对象类型,扩容时,一定不能够使用memcpy&realloc!!!
理由:这种操作是浅拷贝【如果对象的属性里有指针,则指针指向的是同一空间(访问的是同一内存),这种方法不可取,但如果没有指针,则无所谓】
在代码上如何解决浅拷贝问题?
1.提供自定义的拷贝构造函数和赋值重载函数operator=
2.拷贝构造函数和赋值重载函数声明成private的
一般来说最好自己写深拷贝,重新定义一个堆空间,将之前的内容复制到该空间。
CQueue(const CQueue &src)//队列
{
_pQue = new int[src._size];
memcpy(_pQue, src._pQue, sizeof(int)*src._size);
如果队列里放的是内置类型,可以用memcpy,如果是对象或带指针的,就只能用循环,一个一个赋值。
_front = src._front;
_rear = src._rear;
_size = src._size;
}
优化规则:
用临时对象初始化同类型新对象的时候,临时对象就不产生了。所以用构造临时对象的方式,直接构造新对象就行了
Test t3 = Test(10, 10);
在优化中注意的地方:
1:函数调用传参要传对象的引用! eg:Test GetTestObject(Test &t)
2:函数返回值当中不要返回一个已经存在的对象,返回临时对象!!! eg:return Test(value);
3:用初始化的方式接收一个返回值为对象的函数 eg: Test t2 = GetTestObject(t1);
补充解释:
函数返回值:小于4字节用eax寄存器。小于8字节,用eax,edx两个寄存器。当返回值大于8字节时,会产生临时量,当返回的是对象不管多大都会产生临时量,因为对象的构造一定会分配内存。
在调用函数之前会查看函数返回值如果返回值不为空,这个时候就已经在main函数栈帧上开辟了临时量的空间,就算函数没有参数,不需要参数传递,但其实还是传递了该临时量空间的地址。函数返回局部变量的时候就拷贝到这个临时量上了。
在了解了上述的基础上,我来详细解释下优化规则:
1、函数调用传参要传对象的引用! 如果不传引用,而是用值传递的方法,就会多实现一步对参数t的拷贝构造,并且出函数也会调用析构函数。
2、函数返回值中返回临时对象! 如果返回的是已存在的对象,这个对象肯定是函数里的局部变量,首先建立它的时候就会调用构造函数,出函数的时候先拷贝构造main函数栈帧上的临时对象,再对其本身进行析构。
1、用初始化的方式接收一个返回值为对象的函数! 如果不以初始化的方式接收,也就是说用的是已经存在的对象接收,当然会使用临时量调用赋值函数的重载。并且这个临时量也会析构。
内存分配:
我一直认为了解内存分配,可以更全面的理解代码。但之前一直是零零散散使用,并没有全面的认识,今天我打算对其进行简单整理:
大体上是这样分配的,如果浏览该博文的哪位大佬发现有什么需要修改或补充的地方,还请及时告知我,不胜感激。