4

As I'm getting into Point Cloud Library (PCL) I'm encountering some confusion on when to declare point clouds with ::Ptr verses without this.

It seems to work either way, for example both of these programs compile, run, and product the expected results (writing a random 20 point cloud to file):

// WriteCloud.cpp

#include <iostream>

#include <pcl/common/common_headers.h>
#include <pcl/io/pcd_io.h>

int main(void)
{
  std::cout << "\n\n" << "starting program" << "\n\n";

  pcl::PointCloud<pcl::PointXYZ> cloud;    // !!! without ::Ptr !!!

  int numPoints = 20;

  for (int i = 0; i < numPoints; i++)
  {
    pcl::PointXYZ point;

    point.x = 1024 * rand() / (RAND_MAX + 1.0f);
    point.y = 1024 * rand() / (RAND_MAX + 1.0f);
    point.z = 1024 * rand() / (RAND_MAX + 1.0f);

    cloud.points.push_back(point);
  }

  // for simplicity, use an "unorganized" cloud, "width" = num points, "height" = 1
  cloud.width = (int)cloud.points.size();
  cloud.height = 1;

  pcl::io::savePCDFileASCII("my_cloud.pcd", cloud);

  std::cout << "\n\n" << "program complete" << "\n\n";

  return (0);
}

and

// WriteCloudPtr.cpp

#include <iostream>

#include <pcl/common/common_headers.h>
#include <pcl/io/pcd_io.h>

int main(void)
{
  std::cout << "\n\n" << "starting program" << "\n\n";

  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);      // !!! with ::Ptr !!!

  int numPoints = 20;

  for (int i = 0; i < numPoints; i++)
  {
    pcl::PointXYZ point;

    point.x = 1024 * rand() / (RAND_MAX + 1.0f);
    point.y = 1024 * rand() / (RAND_MAX + 1.0f);
    point.z = 1024 * rand() / (RAND_MAX + 1.0f);

    cloud->points.push_back(point);
  }

  // for simplicity, use an "unorganized" cloud, "width" = num points, "height" = 1
  cloud->width = (int)cloud->points.size();
  cloud->height = 1;

  pcl::io::savePCDFileASCII("my_cloud.pcd", *cloud);

  std::cout << "\n\n" << "program complete" << "\n\n";

  return (0);
}

Is there a rule of thumb as to which should be used? More specifically, here are some questions I have:

-In all of the PCL GitHub examples https://github.com/PointCloudLibrary/pcl/tree/master/examples the programs use ::Ptr, and on the website most (but not all) of the examples use ::Ptr. Also, for the most part, the examples I've found not using ::Ptr seem to be very old. Based on this more than anything I'm under the impression that ::Ptr is generally regarded as the current PCL standard, is this correct?

-The non-::Ptr way seems simpler, is there any disadvantage to the non-::Ptr way that is not apparent? Before somebody says "passing these into a function would make a copy of the cloud and therefore be inefficient" I would pass by reference so as to not make copies unnecessarily.

-Clearly ::Ptr is a typedef (essentially a renaming) of boost::shared_ptr. Still, it makes me uncomfortable to use pointers when not necessary as funny things can happen in odd situations. For example the accepted answer to this post Create a pcl::PointCloud::Ptr from a pcl::PointCloud mentions an odd conversion situation which could seem to cause a crash. Are there any risks with using the ::Ptr way in certain situations that PCL users should be aware of?

Martin Valgur
  • 5,793
  • 1
  • 33
  • 45
cdahms
  • 3,402
  • 10
  • 49
  • 75

1 Answers1

1

IMHO, it's a design flaw in PCL to define function arguments for PointCloud as a PointCloud::Ptr since the functions don't care if the object is allocated on the stack or on the heap and neither do they make use of ownerships.

To your question, declare your objects as pointers when you know that your object will get very large, otherwise stick to non pointer version.

serkan.tuerker
  • 1,681
  • 10
  • 20
  • > "neither do they make use of ownerships" This is not correct. PCL algorithm objects are stateful and take ownership of input point clouds. This was a conscious design choice and the intended usage is that the algorithm is first configured, then inputs are set, then the "process" method is called, then optionally other methods can be called to get by-products of processing. – taketwo Sep 24 '19 at 11:58
  • Why do you say they take ownership of the objects? Using a `boost::shared_ptr` means that the object is shared, so the algorithm is not taking ownership. In order to check if the input is valid, you could also just check if the input point cloud is empty or not. – serkan.tuerker Sep 24 '19 at 18:45
  • Sorry for misleading statement, you are right, I meant something different. I should have written "algorithm objects are stateful and SHARE ownership of input point clouds". However, I don't understand your next suggestion about input validation. – taketwo Sep 25 '19 at 12:36
  • In many of the algorithms the `process` function has a precondition, where a check of the likes of `if(!cloud_) return;`. You could also just check if the cloud is empty with `if(cloud.empty()) return;`. No need for pointer nonsense. – serkan.tuerker Sep 25 '19 at 19:15
  • But how would you then guarantee that the original cloud did not go out of scope and was not destroyed in-between `setInput` and `process` calls? – taketwo Sep 26 '19 at 12:59