关于指针和内存的几个问题 一、"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 的场合。 八、该怎麽用 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:"，如果你想要有衍生类别的话）。 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; }