user3833261 user3833261 - 3 months ago 13
C++ Question

How can I know what makes an incomplete type incomplete for error: arithmetic on a pointer to an incomplete type

I have tried to define my own PointT type to give me XYZRGBA and intensity values in a single point. I tried to follow the conventions laid out in this article on the point cloud library website: http://pointclouds.org/documentation/tutorials/adding_custom_ptype.php

The implementation for PointXYZRGBAI is in a .CPP file for one of my classes, but I forward declare it in a header file that is included by other header files. The implementation is in LidarFile.cpp:

struct PointXYZRGBAI{
PCL_ADD_POINT4D;
union{
struct{
float intensity;
uint32_t rgba;
};
float data_c[4];
};
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
} EIGEN_ALIGN_16;

POINT_CLOUD_REGISTER_POINT_STRUCT(PointXYZRGBAI,
(float, x, x)
(float, y, y)
(float, z, z)
(float, intensity, intensity)
(uint32_t, rgba, rgba)
)

inline std::ostream& operator << (std::ostream& os, const PointXYZRGBAI& p){
os << "(" << p.x << ", " << p.y << ", " << p.z << " - " << p.intensity << " - " << p.rgba << ")";
return (os);
}


and the forward declaration is inside a header file name PointXYZRGBAI.h

#define PCL_NO_PRECOMPILE

#ifndef POINTXYZRGBAI_H
#define POINTXYZRGBAI_H
#endif

#include <pcl/point_types.h>

struct PointXYZRGBAI;

inline std::ostream& operator << (std::ostream& os, const PointXYZRGBAI& p);


From my very basic understanding of structs, I need to forward declare the struct so that the compiler understands that PointXYZRGBAI is indeed a struct and not some unknown type during compiling, and fills in the blanks afterwards with the actual implementation. But this is seemingly challenged by the fact that when I declare any member instance variable that uses the templated type PointXYZRGBAI, an error is thrown: arithmetic on a pointer to an incomplete type 'PointXYZRGBAI, like when I declare a point cloud that uses the struct PointXYZRGBAI:

pcl::PointCloud<PointXYZRGBAI> cl; //Error: arithmetic on a pointer to an incomplete type 'PointXYZRGBAI'
//__alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__end_));
// __alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__end_));


It would appear that there are undefined operations taking place on the PointXYZRGBAI type. So what should I do? Do I need to somehow implement the struct before the LidarFile.h header? Just for reference, here is the full error stack trace:

In file included from /Users/wfehrnstrom/Demeter/core.cpp:9:
In file included from /usr/local/include/boost/thread/thread.hpp:12:
In file included from /usr/local/include/boost/thread/thread_only.hpp:17:
In file included from /usr/local/include/boost/thread/pthread/thread_data.hpp:24:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:424:68: error:
arithmetic on a pointer to an incomplete type 'PointXYZRGBAI'
__alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__end_));
^ ~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:368:29: note:
in instantiation of member function
'std::__1::__vector_base<PointXYZRGBAI,
Eigen::aligned_allocator_indirection<PointXYZRGBAI> >::__destruct_at_end'
requested here
void clear() _NOEXCEPT {__destruct_at_end(__begin_);}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:451:9: note:
in instantiation of member function
'std::__1::__vector_base<PointXYZRGBAI,
Eigen::aligned_allocator_indirection<PointXYZRGBAI> >::clear' requested
here
clear();
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iterator:1244:75: note:
in instantiation of member function
'std::__1::__vector_base<PointXYZRGBAI,
Eigen::aligned_allocator_indirection<PointXYZRGBAI> >::~__vector_base'
requested here
...<class _Tp, class _Alloc> friend class _LIBCPP_TYPE_VIS_ONLY vector;
^
/Users/wfehrnstrom/Demeter/LidarFile.h:20:7: note: in instantiation of member
function 'pcl::PointCloud<PointXYZRGBAI>::~PointCloud' requested here
class LidarFile{
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1527:14: note:
in instantiation of function template specialization
'std::__1::allocator_traits<std::__1::allocator<LidarFile>
>::__destroy<LidarFile>' requested here
{__destroy(__has_destroy<allocator_type, _Tp*>(), __a, __p);}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:424:25: note:
in instantiation of function template specialization
'std::__1::allocator_traits<std::__1::allocator<LidarFile>
>::destroy<LidarFile>' requested here
__alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__end_));
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:368:29: note:
in instantiation of member function 'std::__1::__vector_base<LidarFile,
std::__1::allocator<LidarFile> >::__destruct_at_end' requested here
void clear() _NOEXCEPT {__destruct_at_end(__begin_);}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:451:9: note:
in instantiation of member function 'std::__1::__vector_base<LidarFile,
std::__1::allocator<LidarFile> >::clear' requested here
clear();
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iterator:1244:75: note:
in instantiation of member function 'std::__1::__vector_base<LidarFile,
std::__1::allocator<LidarFile> >::~__vector_base' requested here
...<class _Tp, class _Alloc> friend class _LIBCPP_TYPE_VIS_ONLY vector;
^
/Users/wfehrnstrom/Demeter/PointXYZRGBAI.h:9:8: note: forward declaration of
'PointXYZRGBAI'
struct PointXYZRGBAI;
^
In file included from /Users/wfehrnstrom/Demeter/core.cpp:9:
In file included from /usr/local/include/boost/thread/thread.hpp:12:
In file included from /usr/local/include/boost/thread/thread_only.hpp:17:
In file included from /usr/local/include/boost/thread/pthread/thread_data.hpp:24:


Any help or clarification would be greatly appreciated.

Answer

You can do very few things with an incomplete type.

If you forward declare a struct or a class as you did, you can only declare a pointer to such an object:

  • You can't even increment or decrement such a pointer because this would require the compiler to know the size of the object (i.e. know its declaration).
  • You can't allocate a new object either, as the constructors are not known, and neither are the alignment requirements.

So you have to put the struct definition in the header:

#define PCL_NO_PRECOMPILE

#ifndef POINTXYZRGBAI_H
#define POINTXYZRGBAI_H

#include <pcl/point_types.h>

struct PointXYZRGBAI{
  PCL_ADD_POINT4D;  // macro in pcl/point_types.h that defines some member functions
  union{
    struct{
      float intensity;
      uint32_t rgba;
    };
    float data_c[4];
  };
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW  // eigen/core seems included in pcl/point_types.h 
} EIGEN_ALIGN_16;

inline std::ostream& operator << (std::ostream& os, const PointXYZRGBAI& p);

#endif

The implementation of the functions (and the registration macro) shall remain in the cpp file.