函數的參數傳遞能夠簡單分類爲「傳值」和「傳引用」。app
聲明函數時,形參帶引用「&」,則函數調用時,是把實參所在的內存直接傳給函數所開闢的棧內存。在函數內對形參的修改至關於對實參也進行修改。函數
聲明函數時,形參不帶引用,則函數調用時,是把實參拷貝一份做爲形參。從內存上看,存在兩個存放相同變量的區域,分別是實參和形參。在函數中對形參的修改,都不會對實參產生影響。函數退出後,形參所在的棧內存所有銷燬。spa
對智能指針shared_ptr的通俗理解。設計
shared_ptr之因此可以作到在指針生命週期結束後自動銷燬,得益於兩個經典設計:指針
1)用類封裝裸指針獲得智能指針,在類的析構函數中,執行指針的delete操做;code
2)類內有兩個成員變量,一個是裸指針,一個是計數器;blog
當計數器計數歸零時,智能指針自動調用其析構函數,銷燬指針,釋放內存。生命週期
智能指針做爲函數的參數。內存
1)智能指針做爲函數的傳值參數,執行new操做get
main函數片斷以下,
PointCloudPtr targetCloudPtr; targetCloudPtr = lidar_->GetNewCloud(); if (targetCloudPtr == 0) return; PointCloudPtr processTarPtr(new PointCloudType); ExtrPlanes_->run_Plane_Extraction(targetCloudPtr, processTarPtr); std::cout << "process target point cloud size : " << processTarPtr->points.size() << std::endl;
聲明瞭一個PCL的智能指針 processTarPtr ,執行new操做以後, processTarPtr 中便有了一個 PointCloudType 的裸指針成員變量,同時計數器+1,此時計數器=1.
函數 run_Plane_Extraction 的定義以下,
void Extr_PLANEFEATURE::run_Plane_Extraction(PointCloudPtr inPtr, PointCloudPtr outPtr) { PointCloudPtr MLS_pointcloud(new PointCloudType); // // 給MLS_pointcloud賦值 // outPtr = MLS_pointcloud; }
實參processTarPtr將拷貝一份做爲形參,同時計數器+1,此時計數器=2.
在函數中對形參的修改都不會對實參產生影響。所以,函數執行完畢,outPtr所指向的棧內存所有銷燬。
此時,在main函數中讀取processTarPtr指針的值,返回值爲0。此時程序並不會崩潰。等到這個0值對main函數中其餘操做產生影響時,程序纔會報錯。
Invalid or empty point cloud dataset given! Invalid or empty point cloud dataset given! [ndtMap-2] process has died [pid 25597, exit code -8, cmd /home/gordon/fase_ws/devel/lib/ddd_wall_mapping/ndtMap __name:=ndtMap __log:=/home/gordon/.ros/log/d150b30c-aecf-11e9-8009-9cda3e942fe1/ndtMap-2.log]. log file: /home/gordon/.ros/log/d150b30c-aecf-11e9-8009-9cda3e942fe1/ndtMap-2*.log
2)智能指針做爲函數的傳值參數,不執行new操做
main函數作以下修改,即不執行智能指針的new操做。
PointCloudPtr targetCloudPtr; targetCloudPtr = lidar_->GetNewCloud(); if (targetCloudPtr == 0) return; PointCloudPtr processTarPtr; ExtrPlanes_->run_Plane_Extraction(targetCloudPtr, processTarPtr); std::cout << "process target point cloud size : " << processTarPtr->points.size() << std::endl;
聲明瞭一個智能指針而不進行new操做,那麼這個指針一直個是空指針,即null。計數器一直爲0.
函數run_Plane_Extraction的調用結果與上面例子相同。回到main函數,訪問空指針processTarPtr,程序當即崩潰。報錯以下,
ndtMap: /usr/include/boost/smart_ptr/shared_ptr.hpp:648: typename boost::detail::sp_member_access<T>::type boost::shared_ptr<T>::operator->() const [with T = pcl::PointCloud<pcl::PointXYZI>; typename boost::detail::sp_member_access<T>::type = pcl::PointCloud<pcl::PointXYZI>*]: Assertion `px != 0' failed. [ndtMap-2] process has died [pid 15323, exit code -6, cmd /home/gordon/fase_ws/devel/lib/ddd_wall_mapping/ndtMap __name:=ndtMap __log:=/home/gordon/.ros/log/d150b30c-aecf-11e9-8009-9cda3e942fe1/ndtMap-2.log]. log file: /home/gordon/.ros/log/d150b30c-aecf-11e9-8009-9cda3e942fe1/ndtMap-2*.log
3)智能指針做爲函數的傳引用參數
爲解決上述問題,函數 run_Plane_Extraction 對形參的修改可以等同於對形參進行修改。即,咱們但願可以在函數 run_Plane_Extraction 結束後,將其中的形參outPtr所指向的內存保存下來。
對於上述2個例子,其修改方式都同樣,把函數 run_Plane_Extraction 的形參改爲傳引用參數。
void Extr_PLANEFEATURE::run_Plane_Extraction(PointCloudPtr inPtr, PointCloudPtr& outPtr) { PointCloudPtr MLS_pointcloud(new PointCloudType); // // 給MLS_pointcloud賦值 // outPtr = MLS_pointcloud; }
傳引用參數,把實參所在的內存直接傳遞給函數做爲形參,對形參的修改等同於對實參的修改。
函數 run_Plane_Extraction 結束之後,不會銷燬實參指向的內存!
問題成功解決!