1. 程式人生 > >【C++】【指標】把指標傳出去使用的函式,指向指標的指標

【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 及以上的新特性。。。暫時還不會啊,路漫漫啊。。。