一
函数的参数传递可以简单分类为“传值”和“传引用”。
声明函数时,形参带引用“&”,则函数调用时,是把实参所在的内存直接传给函数所开辟的栈内存。在函数内对形参的修改相当于对实参也进行修改。
声明函数时,形参不带引用,则函数调用时,是把实参拷贝一份作为形参。从内存上看,存在两个存放相同变量的区域,分别是实参和形参。在函数中对形参的修改,都不会对实参产生影响。函数退出后,形参所在的栈内存全部销毁。
二
对智能指针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 结束以后,不会销毁实参指向的内存!
问题成功解决!