1. 程式人生 > >C++ 建構函式使用 ":成員變數(形參)" 的形式給類裡面成員變數賦值,如果成員變數和形參是指標,那麼需要注意的事項

C++ 建構函式使用 ":成員變數(形參)" 的形式給類裡面成員變數賦值,如果成員變數和形參是指標,那麼需要注意的事項

我先把結論列出來:

當成員變數和形參是指標,最好不要使用:成員變數(形參)這樣的形式。因為你可以不是進行:成員變數 = 形參這個方向的賦值,你可能是執行:形參 = 成員變數這個方向的賦值。因為前提,它們都是指標嘛。

今天我遇到了這樣的一個錯誤:

下面的程式,編譯是正常通過的,但是執行卻不行。(我只是將相關的程式碼貼了出來)

class PclView{
public:
    PclView(pcl::visualization::PCLVisualizer * &p);
    void showCloudsLeft(const pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_source,
                        const
pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_target); private: pcl::visualization::PCLVisualizer *p; };
PclView::PclView(pcl::visualization::PCLVisualizer * &p):p(p){
    vp_1 = 1;
    vp_2 = 2;
    // Create a PCLVisualizer object
    p = new pcl::visualization::PCLVisualizer ("Pairwise Incremental Registration example"
); p->createViewPort (0.0, 0, 0.5, 1.0, vp_1); p->createViewPort (0.5, 0, 1.0, 1.0, vp_2); p->removePointCloud ("vp1_target"); } void PclView::showCloudsLeft(const pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_source, const pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_target) { p->removePointCloud ("vp1_target"
); p->removePointCloud ("vp1_source"); pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_h (cloud_target, 0, 255, 0); pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h (cloud_source, 255, 0, 0); p->addPointCloud (cloud_target, tgt_h, "vp1_target", vp_1); p->addPointCloud (cloud_source, src_h, "vp1_source", vp_1); // PCL_INFO ("Press Space to begin the registration.\n"); p-> spinOnce(); }

當我們在main.cpp檔案中定義了一個上面的類的例項化物件後,然後呼叫這個類的showCloudsLeft()方法。編譯程式沒有問題, 但是執行程式就會出現錯誤。

int main(void){
    pcl::visualization::PCLVisualizer *p;
    PclView viewer(p);
    pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_source;
    pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_target;
    viewer.showCloudsLeft(cloud_source, cloud_target);
    return 0;
}

上面的程式執行的時候程式會死在showCloudsLeft()函式裡面的p->removePointCloud ("vp1_target");這段程式碼。原因是:p指標為空。

正確的寫法:

問題出現在PclView::PclView(pcl::visualization::PCLVisualizer * &p)這個建構函式裡面。

正確的寫法有兩種:

PclView::PclView(pcl::visualization::PCLVisualizer * &p){
    this->p = p;
    vp_1 = 1;
    vp_2 = 2;
    // Create a PCLVisualizer object
    this->p = new pcl::visualization::PCLVisualizer ("Pairwise Incremental Registration example");
    this->p->createViewPort (0.0, 0, 0.5, 1.0, vp_1);
    this->p->createViewPort (0.5, 0, 1.0, 1.0, vp_2);
    this->p->removePointCloud ("vp1_target");
}

或者:

PclView::PclView(pcl::visualization::PCLVisualizer * &p):p(p){
    vp_1 = 1;
    vp_2 = 2;
    // Create a PCLVisualizer object
    this->p = new pcl::visualization::PCLVisualizer ("Pairwise Incremental Registration example");
    this->p->createViewPort (0.0, 0, 0.5, 1.0, vp_1);
    this->p->createViewPort (0.5, 0, 1.0, 1.0, vp_2);
    this->p->removePointCloud ("vp1_target");
}

現在問題就解決了。

但是雖然現在的問題是解決了,但是程式還是有潛在問題的。(現在的程式,還沒有達到我們想要的目的。)我們最開始設計這個建構函式,是想將外部通過形參傳入的這個指標能夠與這個例項化物件裡面pcl::visualization::PCLVisualizer * p指標能夠指向同一個東西,然後它們兩個都可以去改變這個東西。

但是現在我們並沒有做到這一點。我們可以使用下面的程式碼驗證:

int main(void){
    pcl::visualization::PCLVisualizer *p;
    PclView viewer(p);
    pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_source;
    pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_target;
    viewer.showCloudsLeft(cloud_source, cloud_target);
    p->removePointCloud ("vp1_target");
    return 0;
}

編譯程式不會出現什麼問題,但是現在執行,程式就會在main()函式裡面的p->removePointCloud ("vp1_target");這段程式碼出現問題。

所以,正真正確的解決辦法是:

PclView::PclView(pcl::visualization::PCLVisualizer * &p){
    vp_1 = 1;
    vp_2 = 2;
    // Create a PCLVisualizer object
    this->p = new pcl::visualization::PCLVisualizer ("Pairwise Incremental Registration example");
    this->p->createViewPort (0.0, 0, 0.5, 1.0, vp_1);
    this->p->createViewPort (0.5, 0, 1.0, 1.0, vp_2);
    this->p->removePointCloud ("vp1_target");
    p = this->p;
}

現在就變成了完美的程式,不會出現問題,也沒有潛在的問題。

出現上面的問題的原因

原因很簡單,完美的設計思想是:希望兩個指標都指向同一個儲存空間,但是,實際上兩個指標沒有指向一個儲存空間,一個指標指向了儲存空間,而一個是空指標,所以就出現了錯誤。