• 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 结束以后,不会销毁实参指向的内存!

    问题成功解决!

  • 相关阅读:
    修复火狐主页被篡改成hao123的办法
    VMware中装Win2012并配置Hyper-v
    Linux下随机密码生成器
    GNS3 桥接虚拟网卡 telnet 实验
    冰点文库下载器停止工作解决办法
    《循序渐进》之简单的DHCP实验
    windows脚本配置ip地址
    phpmyadmin使用中碰到的一些问题
    phpmyadmin导入导出大数据文件的办法
    phpmyadmin的安装和使用
  • 原文地址:https://www.cnblogs.com/gdut-gordon/p/11246867.html
Copyright © 2020-2023  润新知