本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
需求:在函数中 new 一个变量,并将其地址传出去给函数调用者使用。
今天在 coding 时遇到一个错误。我在 Ctrl 类写了一个成员函数 int init(Camera *p),并声明了一个成员变量 Camera *m_pC然后在该函数的定义中这么写的:
int Ctrl::init(Camera *p)
{
m_pC = new Camera();
p = m_pC;
p->open();
ALOGD("m_pC = %p, p = %p", m_pC, p);
return 0;
}
然后在 Manager 类声明了一个成员变量 Ctrl *m_pC, 一个成员变量 Camera *m_pRC,并且在某个位置调用了 Ctrl 类的成员函数 init。
......
int res = m_pC->init(m_pRC);
ALOGD("m_pRC = %p", m_pRC);
......
然后满心欢喜地期待着 Log 打印的 m_pRC 的值和 m_pC、p 的值是一致的。 以便我可以在 Manager 类中的其他地方使用这个指针直接操作 Camera 对象。 然而事实却并非如此!! @@@@@@@@@@@@@@@@分割线@@@@@@@@@@@@@@@@@@
看起来(自以为)很美好的实现了把函数内新建一个对象然后把它的指针抛上来使用。而且,传指针修改可以修改到指针内部的值,这传的不是普通拷贝参数。。。嗯嗯。然而并不是这样的。
其实,如果我们把 Camera* 看做是一个普通类CameraP,而非谁谁谁的指针,那么我上面的代码,可以近似地写成这样:
// Ctrl.h
...
CameraP m_CPC;
int init(CameraP p);
...
// Ctrl.cpp
...
int Ctrl::init(CameraP p)
{
m_CPC = Camera();
p = m_CPC;
p.open();
ALOGD("m_CPC = %p, p = %p", &m_CPC, &p);
return 0;
}
...
// Manager.h
Ctrl * m_pC;
CameraP m_CPRC;
// Manager.cpp
int res = m_pC->init(m_CPRC);
ALOGD("m_CPRC = %p", m_CPRC);
这么一看,就很明显了。我函数调用时传入的指针,并对其赋值。和传入一个 int 并对其赋值,然后期待它能在函数调用之后保留函数对它付过的那个值,简直一样傻。
所以,如果要实现最初的需求,该怎么办?最简单粗暴的方法,就是把 CamreaP m_CPRC的地址传进去,然后再函数内部,对改地址解指针然后对其赋值。看起来像是这样:
// Ctrl.h
...
CameraP m_CPC;
int init(CameraP* p);
...
// Ctrl.cpp
...
int Ctrl::init(CameraP* p)
{
m_CPC = Camera();
*p = m_CPC;
*p.open();
ALOGD("m_CPC = %p, p = %p", &m_CPC, p);
return 0;
}
...
// Manager.h
Ctrl * m_pC;
CameraP m_CPRC;
// Manager.cpp
int res = m_pC->init(&m_CPRC);
ALOGD("m_CPRC = %p", m_CPRC);
这样一来,就跟普通的
int Add(int *result, int b, int c)
{
*result = b+c;
return 0;
}
int a;
Add(&a, 2, 3);
差不多了。那么,我们再把 CameraP还原为 Camera*。那么将会有以下代码:
// Ctrl.h
...
Camera *m_pC;
int init(Camera **p);
...
// Ctrl.cpp
...
int Ctrl::init(Camera
**p)
{
m_pC = new Camera();
*p = m_pC;
*p->open();
ALOGD("m_pC = %p, *p = %p", m_pC, *p);
return 0;
}
...
// Manager.h
Ctrl * m_pC;
Camera *m_pRC;
// Manager.cpp
int res = m_pC->init(&m_pRC);
ALOGD("m_pRC = %p", m_pRC);
这样一来,m_pRC 打印出来的值就和 m_pC 、*p 的值一样了。
指向指针的指针,说起来很绕,其实可以理解为,指针自身的地址。把指针地址传入函数,并对指针地址 解地址 引用(*p),然后用新对象的地址对 *p 进行赋值,就可以修改指针所指向的地址啦。就可以在函数之外通过这个指针,使用在函数之内创建的新对象了。
不过,貌似,据说,这种方法是很拙劣的。。。:)
更新、更优雅的方法,可能是使用 C++11 及以上的新特性。。。暂时还不会啊,路漫漫啊。。。