Interpret a std :: string as std :: vector of char_type character?

I have a template<typename T> function that takes const vector<T>& . In the specified function, I have the vectors cbegin() , cend() , size() and operator[] . As far as I understand, both string and vector use continuous space, so I was wondering if I can reuse the function for both data types in an elegant way.

Can std::string be reinterpreted as std::vector (corresponding) char_type? If so, what would be the limitations?

+5
source share
7 answers

If you create your template only for type const T& and use functions begin() , end() , etc., which share a vector and a string, then your code will work with both types.

+13
source

Go to the STL path and use iterators. Accept the iterator to start, and the iterator will end. It will work with all possible containers, including non-containers such as streams.

+7
source

There is no guarantee that the location of string and vector will be the same. They could theoretically be, but they probably don't have any common implementation. Therefore, you cannot do it safely. See Zan's Answer for a better solution.

Let me explain: if I am a developer of a standard library and decide to implement std :: string like this ...

 template ... class basic_string { public: ... private: CharT* mData; size_t mSize; }; 

and decide to implement std :: vector like this ...

 template ... class vector { public: ... private: T* mEnd; T* mBegin; }; 

When you reinterpret_cast<string*>(&myVector) , you finish interpreting the pointer at the end of your data as a pointer to the beginning of your data and a pointer to the beginning of your data to the size of your data. If the indentation between the members is different, or there are additional members, it can become even stranger and more broken than that.

So, yes, in order for this to be possible to work, they need to store continuous data, but they also need something completely different to be the same between the implementations for it to work.

+6
source

std::experimental::array_view<const char> n4512 is an adjacent character buffer.

Writing your own is not difficult , and it solves this problem and (in my experience) is still a lot.

Both string and vector are compatible with array representation.

This allows you to move your implementation to a .cpp file (and not set it up), gives you the same performance as using std::vector<T> const& and, possibly in the same implementation, avoids code duplication and Uses a lightweight continuous buffer type erase (which is full of delicious keywords).

+5
source

If the key point is that you want to access a contiguous area in memory where instances of a particular char type are stored, then you can define your function as

 void myfunc(const CType *p, int size) { ... } 

to make it clear that you are assuming that they should be contiguous in memory.

Then, for example, to transfer the contents of the vector, the code simply

 myfunc(&myvect[0], myvect.size()); 

and for string

 myfunc(mystr.data(), mystr.size()); 

or

 myfunc(buffer, n); 

for an array.

+2
source

You cannot directly come up with std :: vector to std :: string or vice versa. But using the iterators provided by STL containers allows you to iterate over a vector and a string equally. And if your function requires random access to the container in question, then it will either work.

 std::vector<char> str1 {'a', 'b', 'c'}; std::string str2 = "abc"; template<typename Iterator> void iterator_function(Iterator begin, Iterator end) { for(Iterator it = begin; it != end; ++it) { std::cout << *it << std::endl; } } iterator_function(str1.begin(), str1.end()); iterator_function(str2.begin(), str2.end()); 

Both of these last two function calls will print the same thing.

Now, if you want to write a generic version that parses only characters stored only in a string or in a vector, you could write something that repeats the internal array.

 void array_function(const char * array, unsigned length) { for(unsigned i = 0; i < length; ++i) { std::cout << array[i] << std::endl; } } 

Both functions will do the same in the following scenarios.

 std::vector<char> str1 {'a', 'b', 'c'}; std::string str2 = "abc"; iterator_function(str1.begin(), str1.end()); iterator_function(str2.begin(), str2.end()); array_function(str1.data(), str1.size()); array_function(str2.data(), str2.size()); 

There are always many ways to solve a problem. Depending on what you have, any number of solutions can work. Try both and see which one is best for your application. If you do not know the type of iterator, then you need an iteration of the char array. If you know that you will always have a template type for transferring, then the template template method may be more useful.

+1
source

The way your question is posed at the moment is a bit confusing. If you want to ask: "Is it safe to use the std::vector type for the std::string or vice versa if the vector contains char values ​​of the corresponding type?", Answer: no, don’t even think about it! If you ask: "Can I access the adjacent memory of non-empty sequences of type char if they are of type std::vector or std::string ?" then the answer will be yes, you can (using the data() member function).

0
source

Source: https://habr.com/ru/post/1233287/


All Articles