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


函數的參數傳遞可以簡單分類為“傳值”和“傳引用”。

聲明函數時,形參帶引用“&”,則函數調用時,是把實參所在的內存直接傳給函數所開辟的棧內存。在函數內對形參的修改相當於對實參也進行修改。

聲明函數時,形參不帶引用,則函數調用時,是把實參拷貝一份作為形參。從內存上看,存在兩個存放相同變量的區域,分別是實參和形參。在函數中對形參的修改,都不會對實參產生影響。函數退出后,形參所在的棧內存全部銷毀。

 

對智能指針shared_ptr的通俗理解。

shared_ptr之所以能夠做到在指針生命周期結束后自動銷毀,得益於兩個經典設計:

1)用類封裝裸指針得到智能指針,在類的析構函數中,執行指針的delete操作;

2)類內有兩個成員變量,一個是裸指針,一個是計數器;

當計數器計數歸零時,智能指針自動調用其析構函數,銷毀指針,釋放內存。

 

智能指針作為函數的參數。

1)智能指針作為函數的傳值參數,執行new操作

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 結束以后,不會銷毀實參指向的內存!

問題成功解決!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM