PCL智能指針疑雲 <三> 智能指針做爲函數的傳值參數和傳引用參數

函數的參數傳遞能夠簡單分類爲「傳值」和「傳引用」。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 結束之後,不會銷燬實參指向的內存!

問題成功解決!

相關文章
相關標籤/搜索