指针和引用以及CString实现机制
涵之 发表于 2007-03-18 19:27:42
引用,一个变量的别名,为什么引入别名呢?原因是我们想定义一个变量,他共享另一个变量的
内存空间,使用别名无疑是一个好的选择。变量是什么?是一个内存空间的名字,如果我们给这个
内存空间在起另外一个名字,那就是能够共享这个内存了,引用(别名)的由此而来。
指针,指向另一个内存空间的变量,我们可以通过它来索引另一个内存空间的内容,本身有自己的
内存空间。
二者区别:(1)引用访问一个变量是直接访问,而指针是间接访问。
(2)引用是一个变量的别名,本身不单独分配自己的内存空间,而指针有自己的内存空间。
(3)引用在开始的时候就绑定到了一个内存空间(开始必须赋初值),所以他只能是这个
内存空间的名字,而不能改成其他的,当然可以改变这个内存空间的值.
例如
int i = 3,j = 4;
int &x = i;//成为i的别名
x = j;//不能否认x仍然引用i,并没有成为j的别名,只是修改了x和j共享的内存空间的值.
这点与指针不同,指针在任何时刻都可以改变自己的指向.
指针的引用与正常指针 释放内存的另一例比较
一、代码:
#include <iostream>
using namespace std;
void freePtr1(int* p1)
{
delete p1;
p1 = NULL;
}
void freePtr2(int*& p2)
{
delete p2;
p2 = NULL;
}
void main()
{
int *p1 = new int;
*p1 = 1;
freePtr1(p1);
int *p2 = new int;
*p2 = 2;
freePtr2(p2);
system("pause");
}
思考:在freePtr1和freePtr2 的比较中,你能发现它们的不同点吗?
二、对代码进行解释:
#include <iostream>
using namespace std;
void freePtr1(int* p1)
{
//未释放内存前 -> p1 Address : 0012FDDC p1 value : 003429B8,在这里,p1它也是一个变量,既然是一个变量,那么它将会以值的传递,把外部变量p1传到栈内,在栈内产生一个地址:0012FDDC,当然,它的值不会变仍然是指向堆地址:003429B8 。
delete p1; //系统回收p1值的地址003429B8处的内存。
p1 = NULL;//对p1赋以NULL值即:00000000,注意:p1本身的地址并没有变,变的是p1的值。
//释放内存后 -> p1 Address : 0012FDDC p1 value : 00000000,出栈后,p1由于是一个临时对象,出栈后它会自动被视为无效。
}
void freePtr2(int*& p2)
{
//未释放内存前 -> p2 Address : 0012FEC8 p2 value : 003429B8,p2是一个指针的引用,即引用指向指针,记住引用的特点:对引用的对象直接操作。所以它的地址和值与栈外的main()函数中,p2的值是同一个。
delete p2; //对p2所引用的指针进行释放内存,即:系统回收main()函数中 p2的值 003429B8 地址处的内存。
p2 = NULL;//对main()函数中p2的指针赋以NULL值。
//释放内存后 -> p2 Address : 0012FEC8 p2 value : 00000000,由于操作的对象都是main()函数中的p2,所以它将应用到原变量中。
}
void main()
{
int *p1 = new int;
//释放内存前-> p1 Address : 0012FED4 p1 value : 003429B8
freePtr1(p1);
//释放内存后-> p1 Address : 0012FED4 p1 value : 003429B8
int *p2 = new int;
//释放内存前-> p2 Address : 0012FEC8 p2 value : 003429B8
freePtr2(p2);
//释放内存后-> p2 Address : 0012FEC8 p2 value : 00000000
system("pause");
}
CString实现的机制
CString是通过“引用”来管理串的,“引用”这个词我相信大家并不陌生,象Window内核对象、COM对象等都是通过引用来实现的。而CString也是通过这样的机制来管理分配的内存块。实际上CString对象只有一个指针成员变量,所以任何CString实例的长度只有4字节.
即: int len = sizeof(CString);//len等于4
这个指针指向一个相关的引用内存块,如图: CString str("abcd");
0x04040404 head部,为引用内存块相关信息
str 0x40404040
正因为如此,一个这样的内存块可被多个CString所引用,例如下列代码:
CString str("abcd");
CString a = str;
CString b(str);
CString c;
c = b;
上面代码的结果是:上面四个对象(str,a,b,c)中的成员变量指针有相同的值,都为0x40404040.而这块内存块怎么知道有多少个CString引用它呢?同样,它也会记录一些信息。如被引用数,串长度,分配内存长度。
这块引用内存块的结构定义如下:
struct CStringData
{
long nRefs; //表示有多少个CString 引用它. 4
int nDataLength; //串实际长度. 4
int nAllocLength; //总共分配的内存长度(不计这头部的12字节). 4
};
由于有了这些信息,CString就能正确地分配、管理、释放引用内存块。
如果你想在调试程序的时候获得这些信息。可以在Watch窗口键入下列表达式:
(CStringData*)((CStringData*)(this->m_pchData)-1)或
(CStringData*)((CStringData*)(str.m_pchData)-1)//str为指CString实例
正因为采用了这样的好机制,使得CString在大量拷贝时,不仅效率高,而且分配内存少。