C++20 introduces std::span, a thin generic abstraction for sequences of elements contiguous in memory represented by the beginning and
length. std::span can unify the interface for such sequences, e.g., for plain arrays, std::array,
std::vector, or std::string.
std::span<T const* const> can be constructed of std::vector<T*> without copying it, which makes it well
suited for const-correct interfaces.
std::span can have dynamic or static extent (length). The latter is useful for compilers to optimize the handling of arrays of size
known at compile time.
This rule reports:
  -  functions that accept a span by means of a plain array or a pointer to the beginning of a sequence and its length 
 
  -  functions that accept 
begin and end iterators of a std::array or a std::vector  
  -  functions that accept 
std::vector<T const*> and are called with a temporary copy of std::vector<T*>
  created just to satisfy the type signature of the argument.  
  -  functions that accept 
std::vector<T*> and never modify the objects pointed to by its elements.  
  -  const member functions that return a reference or a copy of a 
std::vector<T*> field.  
Noncompliant code example
void addOdd(int* arr, size_t size) { // Noncompliant: replace ptr+size with std::span
  for (int i = 0; i*2 + 1 < size; ++i) {
    arr[i*2] += arr[i*2 + 1];
  }
}
void addOdd(std::vector<int>::iterator begin, std::vector<int>::iterator end) { // Noncompliant
  for (auto iter = begin; iter != end && iter + 1 != end; iter += 2) {
    *iter += *(iter + 1);
  }
}
bool oddAre0(const std::vector<int*>& nums) { // Noncompliant: use std::span<const int*>
  for (int i = 0; 2*i + 1 < std::size(nums); ++i) {
    if (0 != *nums[2*i + 1]) {
      return false;
    }
  }
  return true;
}
bool oddAre0(const std::vector<int const*>& nums) { // Noncompliant: use std::span<int const*>
  for (int i = 0; 2*i + 1 < std::size(nums); ++i) {
    if (0 != *nums[2*i + 1]) {
      return false;
    }
  }
  return true;
}
std::vector<int*> getNums();
void caller() {
  std::vector<int*> nums = getNums();
  if (oddAre0(std::vector<int const*>{nums.begin(), nums.end()})) { // This copy is verbose and slow
    // ...
  }
}
class A {
  std::vector<int*> myNums;
public:
  const std::vector<int*>& getMyNums1() const { // Noncompliant: caller can modify *a.myNums[1]
    return myNums;
  }
  std::vector<int const*> getMyNums2() const {
    return std::vector<int const*>{myNums.begin(), myNums.end()}; // Noncompliant: expensive copy
  }
};
Compliant solution
void addOdd(std::span<int> span) { // Compliant
  for (int i = 0; i*2 + 1 < std::size(span); ++i) {
    span[i*2] += span[i*2 + 1];
  }
}
bool oddAre0(std::span<int const* const> nums) { // Compliant
  for (int i = 0; 2*i + 1 < std::size(nums); ++i) {
    if (0 != *nums[2*i + 1]) {
      return false;
    }
  }
  return true;
}
std::vector<int*> getNums();
void caller() {
  std::vector<int*> nums = getNums();
  if (oddAre0(nums)) { // No copy
    // ...
  }
}
class A {
  std::vector<int*> myNums;
public:
  std::span<int const* const> getMyNums() const { // Compliant: const-correct
    return myNums; // No copy
  }
};