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;
}
現在就變成了完美的程式,不會出現問題,也沒有潛在的問題。
出現上面的問題的原因
原因很簡單,完美的設計思想是:希望兩個指標都指向同一個儲存空間,但是,實際上兩個指標沒有指向一個儲存空間,一個指標指向了儲存空間,而一個是空指標,所以就出現了錯誤。