std::vector
is considered to be the owner of the underlying buffer. You can change the buffer but this change causes allocation i.e. making a copy of the source buffer which you don't want (as stated in the question).
You could do the following:
#include <vector>
int main() {
char* source = new char[3] { 1, 2, 3 };
std::vector<char> target;
target.resize(3);
target.assign(source, source + 3);
delete[] source;
return 0;
}
but again std::vector::assign
:
Replaces the contents with copies of those in the range [first, last).
So copy is performed again. You can't get away from it while using std::vector
.
If you don't want to copy data, then you should use std::span
from C++20 (or create your own span) or use std::string_view
(which looks suitable for you since you have an array of char
s).
1st option: Using std::string_view
Since you are limited to C++17, std::string_view
might be perfect for you. It constructs a view of the first 3 characters of the character array starting with the element pointed by source
.
#include <iostream>
#include <string_view>
int main() {
char* source = new char[3] { 1, 2, 3 };
std::string_view strv( source, 3 );
delete[] source;
return 0;
}
2nd option: Using std::span
from C++20
std::span
comes from C++20 so it might not be the most perfect way for you, but you might be interested in what it is and how it works. You can think of std::span
as a bit generalized version of std::string_view
because it is a contiguous sequence of objects of any type, not just characters. The usage is similar as with the std::string_view
:
#include <span>
#include <iostream>
int main() {
char* source = new char[3] { 1, 2, 3 };
std::span s( source, 3 );
delete[] source;
return 0;
}
3rd option: Your own span
If you are limited to C++17, you can think of creating your own span
struct. It might still be an overkill but let me show you (btw take a look at this more elaborated answer):
template<typename T>
class span {
T* ptr_;
std::size_t len_;
public:
span(T* ptr, std::size_t len) noexcept
: ptr_{ptr}, len_{len}
{}
T& operator[](int i) noexcept {
return *ptr_[i];
}
T const& operator[](int i) const noexcept {
return *ptr_[i];
}
std::size_t size() const noexcept {
return len_;
}
T* begin() noexcept {
return ptr_;
}
T* end() noexcept {
return ptr_ + len_;
}
};
int main() {
char* source = new char[3] { 1, 2, 3 };
span s( source, 3 );
delete[] source;
return 0;
}
So the usage is the same as with the C++20's version of std::span
.