Search code examples
c++stdstring-view

Best way to find distance between beginning of string_view and its underlying string


Given an std::string s and std::string_view s_view. What is the "best" way to find the distance between the beginning of s_view and s? By "best" I mean what works safely for all of the main C++ compilers?

The two options I can think of are illustrated by the code example below. I am unsure if these two ways of doing it will always work on all main compilers. Also, I can't help but feeling that there is a more "proper" way of doing it, but I couldn't find any std::string or std::string_view methods that would achieve this.

main.cpp

#include <iostream>
#include <string>

int main() {
  std::string s{"0123456789"};
  std::string_view s_view{s.data() + 3, 4};
  std::cout << "Pointer difference: "
            << (s_view.data() - s.data()) << std::endl;
  std::cout << "Iterator distance: "
            << std::distance(std::string_view{s}.begin(), s_view.begin())
            << std::endl;
  return 0;
}

Compiled on a mac with Apple clang version 11.0.0 using clang++ main.cpp -std=c++11. It prints:

Pointer difference: 3
Iterator distance: 3

Solution

  • std::string_view has no concept of the std::string it is viewing. All it knows is the starting char* data pointer it was given.

    It is undefined behavior to compare iterators from different containers, even if they refer to the same underlying data.

    So, your only option is to compare raw pointers, like you do in your "Pointer difference" example. If you want to compare iterators, you will have to dereference them into pointers first, eg:

    std::cout << "Pointer distance via Iterators: "
                << (&*s_view.begin() - &*s.begin())
                << std::endl;
    

    Live Demo