Since C++17 you can use std::string_view, which was created for viewing part of a character buffer without copying.
std::cout << std::string_view(pBegin, pEnd - pBegin);
pEnd must point to one past the last character to print, like how iterators in C++ work, instead of the last character to print.
In older C++ standards boost::string_ref is an alternative. Newer boost versions also have boost::string_view with the same semantics as std::string_view. Newer C++ standard also has std::span which is a little bit similar in purpose. See Differences between boost::string_ref and boost::string_view.
If you use Qt then there's also QStringView and QStringRef although unfortunately they're used for viewing QString which stores data in UTF-16 instead of UTF-8 or a byte-oriented encoding.
However if you also need to process the string by some functions that require null-terminated string without any external libraries then there's a simple solution (assuming your string is modifiable):
char tmpEnd = *pEnd; // backup the after-end character
*pEnd = '\0';
std::cout << pBegin; // use it as normal C-style string, like dosomething(pBegin);
*pEnd = tmpEnd; // restore the char
In this case make sure that pEnd still points to an element inside the original array and not one past the end of it.
In fact I've just found out that busybox grep also uses that technique to print out the matches without allocating more memory.
See also How do I print a string between two pointers?, which addresses a similar problem in the C language.
std::string( pBegin, pEnd )? That's the natural way of doing it (and the copy won't be noticeable compared to the time taken by the actual output).std::ostream, which can bestd::stringstream. where the difference may count.