【C++】【指標】把指標傳出去使用的函式,指向指標的指標
需求:在函式中 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 及以上的新特性。。。暫時還不會啊,路漫漫啊。。。