今天在写一个Binary Search Tree的程序时,发现其插入有问题,下面是插入程序,每次插入完成后,节点还是NULL。
template<typename Object>
void CMyTree<Object>::insert(const Object& element, BinaryNode<Object>* node)
{
if(node == NULL)
node = new BinaryNode<Object>(element); //新建节点,插入
else if(element < node->element)
insert(element, node->left); //从左边递归
else if(node->element < element)
insert(element, node->right); //从右边递归
}
仔细检查后发现了问题的所在,我使用了函数指针参数来申请动态内存。突然想起在《高质量C/C++编程》一书中,作者曾提出了“
如果函数的参数是一个指针,不要指望用该指针去申请动态内存”,而我正犯了这个错误。下面将结合该书对此问题做深入分析,以此记录,避免以后再犯错。
我们将上述问题抽象出来,如下代码:
#include <iostream>
using namespace std;
void func(int* t)
{
t = new int;
}
int main()
{
int* test =NULL;
func(test);
delete test;
system("pause");
return 0;
}
首先来分析下指针参数传递的原理。编译器总是要给每个函数参数创建一个临时副本,例如指针参数m的临时副本是_m,_m=m,此时_m和m指向同一段内存地址,如图1所示。因此,当我们修改地址1的内容时,实际也就修改了m所指向的内存的内容,这一点与我们平时使用指针参数的目的是一致的。然而,当我们修改_m的值(为其申请动态内存)时,只是将_m指向另一段内存地址(地址2),而m仍然指向地址1,这就相当于值传递了,是无法更改变量内容的。同时,这么做的话为造成内存泄露。
如果需要通过指针参数来申请动态内存,有三种做法:
(1)使用指向指针的指针参数,即func(int** t)
void func(int** t)
{
*t = new int;
}
<pre class="cpp" name="code">int main()
{
int* test =NULL;
func(&test);
delete test;
system("pause");
return 0;
}
(2)使用指针的引用,即func(
int*& t)
void func(int* &t)
{
t = new int;
}
int main()
{
int* test =NULL;
func(test);
delete test;
system("pause");
return 0;
}
(3)使用函数返回值来传递动态内存,即
int* func()
int* func()
{
int* t = new int;
return t;
}
int main()
{
int* test =func();
delete test;
system("pause");
return 0;
}