关于指针和内存的几个问题
副标题#e#
一、"delete p" 会删去 "p" 指针,照旧它指到的资料,"*p" ?
该指针指到的资料。"delete" 真正的意思是:「删去指针指到的对象」(delete the thing pointed to by)。同样的英文误用也产生在 C 语言的「释放」指标所指向的影象体("free(p)"真正的意思是:"free_the_stuff_pointed_to_by(p)" )。
二、能 "free()" 掉由 "new" 设置到的、"delete" 掉由 "malloc()" 设置到的影象体吗?
不可。在同一个程式里,利用 malloc/free 及 new/delete 是完全正当、公道、安详的;但 free 掉由 new 设置到的,或 delete 掉由 malloc 设置到的指标则是不正当、不公道的。
三、为什麽该用 "new" 而不是 malloc() ?
建构子/解构子、型别安详性、可被包围(overridability)。建构子/解构子:和 "malloc(sizeof(Fred))" 差异,"new Fred()" 还会去呼唤Fred 的建构子。同理,"delete p" 会去呼唤 "*p" 的解构子。
型别安详性:malloc() 会传回一个不具型别安详的 "void*",而 "new Fred()" 则会传回正确型态的指标(一个 "Fred*")。
可被包围:"new" 是个可被物件种别包围的运算子,而 "malloc" 不是以「各个种别」作为包围的基准。
四、为什麽 C++ 不替 "new" 及 "delete" 搭配个 "realloc()" ?
制止你发生意外。当 realloc() 要拷贝设置区时,它做的是「逐位元 bitwise」的拷贝,这会弄坏大
部份的 C++ 物件。不外 C++ 的物件应该可以自我拷贝才对:用它们本身的拷贝建构子或设定运算子。
五、该奈何设置/释放阵列?
用 new[] 和 delete[] :
Fred* p = new Fred[100];
//…
delete [] p;
每当你在 "new" 运算式顶用了 "[…]" 的话,你就 *!*必需*!* 在 "delete" 告诉中利用 "[]" 。这语法是须要的,因为「指向单一元素的指标」与「指向一个阵列的指标」在语法上并无法区分隔来。
六、万一我忘了将 "[]" 用在 "delete" 由 "new Fred[n]" 设置到的阵列,会产生什麽事?
劫难。这是程式者的--而不是编译器的--责任,去确保 new[] 与 delete[] 的正确配对。若你弄错了,编译器不会发生任何编译期或执行期的错误讯息。会萃(heap)被粉碎是最大概的了局,或是更糟的,你的程式会当掉。
七、成员函数做 "delete this" 的行动是正当的(而且是好的)吗?
只要你小心的话就没事。所谓的「小心」是:
1) 你得 100% 确定 "this" 是由 "new" 设置来的(而非 "new[]",亦非自订的 "new" 版本,必然要是最原始的 "new")。
2) 你得 100% 确定该成员函数是此物件最後一个会去呼唤的。
3) 做完自杀的行动 ("delete this;") 後,你不能再去碰 "this" 的物件了,包罗资料及运作行为在内。
4) 做完自杀的行动 ("delete this;") 後,你不能再去碰 "this" 指标了。换句话说,你不能查察它、将它与其他指标或是 NULL 对较量、印出其值、对它转型、对它做任何工作。
很自然的,这项告诫也合用於:当 "this" 是个指向基底类此外指标,而解构子不是virtual 的场所。
#p#副标题#e#
八、该怎麽用 new 来设置多维阵列?
有许多要领,端视你对阵列巨细的伸缩性之要求而定。极度一点的景象,假如你在编译期就知道所有阵列的维度,你可以静态地设置(就像 C 一样):
class Fred { /*...*/ };
void manipulateArray()
{
Fred matrix[10][20];
//利用 matrix[i][j]...
//不须特地去释放该阵列
}
另一个极度环境,假如你但愿该矩阵的每个小块都能纷歧样大,你可以在自由影象体里设置之:
void manipulateArray(unsigned nrows, unsigned ncols[])
//'nrows' 是该阵列之列数。
//所以正当的列数为 (0, nrows-1) 开区间。
//'ncols[r]' 则是 'r' 列的行数 ('r' 值域为 [0..nrows-1])。
{
Fred** matrix = new Fred*[nrows];
for (unsigned r = 0; r < nrows; ++r)
matrix[r] = new Fred[ ncols[r] ];
//利用 matrix[i][j]...
//释放就是设置的反行动:
for (r = nrows; r > 0; --r)
delete [] matrix[r-1];
delete [] matrix;
}
九、奈何确保某类此外物件都是用 "new" 成立的,而非区域或整体/静态变数?
确定该类此外建构子都是 "private:" 的,并界说个 "friend" 或 "static" 函数,来传回一个指向由 "new" 制作出来的物件(把建构子设成 "protected:",假如你想要有衍生类此外话)。
#p#分页标题#e#
class Fred { //只答允 Fred 动态设置出来
public:
static Fred* create() { return new Fred(); }
static Fred* create(int i) { return new Fred(i); }
static Fred* create(const Fred& fred) { return new Fred(fred); }
private:
Fred();
Fred(int i);
Fred(const Fred& fred);
virtual ~Fred();
};
main()
{
Fred* p = Fred::create(5);
...
delete p;
}