I would probably write:
if (pa == pb || (pa && pb && *pa == *pb))
You could get the benefit of that Perl syntax with a function template backed by a helper class that implements comparison:
template <typename T> struct Maybe { T *ptr explicit Maybe(T *ptr) : ptr(ptr) {} bool operator==(const Maybe &other) const { return (ptr == other.ptr) || (ptr && other.ptr && *ptr == *other.ptr); // or whatever other answer to this question you like } bool operator!=(const Maybe &other) const { return !(*this == other); } }; // could make it work for smart pointer types too, // but this is simple template <typename T> Maybe<T> maybe(T *ptr) { return Maybe<T>(ptr); } if (maybe(pa) == maybe(pb)) ...
Obviously that's only worth if it you do this in a lot of different places. And to replace this one use of the Perl syntax, you could just as well have a function template that takes two pointers and returns the result...
pa // NULL == pb // NULLperldoc.perl.org/perlop.html#Logical-Defined-Or