简体   繁体   中英

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

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

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

如果仅针对const T&类型创建模板const T&并使用begin()end()等矢量和字符串共享的函数,则您的代码将同时适用于这两种类型。

Go STL way and use iterators. Accept iterator to begin and iterator to end. It will work with all possible containers, including non-containers like streams.

There is no guarantee the layout of string and vector will be the same. They theoretically could be, but they probably aren't in any common implementation. Therefore, you can't do this safely. See Zan's answer for a better solution.

Let me explain: If I am a standard library implementer and decide to implement std::string like so....

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

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

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

When you reinterpret_cast<string*>(&myVector) you wind up interpreting the pointer to the end of your data as the pointer to the start of your data, and the pointer to the start of your data to the size of your data. If the padding between members is different, or there are extra members, it could get even weirder and more broken than that too.

So yes, in order for this to possibly work they both need to store contiguous data, but they also need quite a bit else to be the same between the implementations for it to work.

std::experimental::array_view<const char> n4512 represents a contiguous buffer of chars.

Writing your own is not hard , and it solves this problem and (in my experience) many more.

Both string and vector are compatible with an array view.

This lets you move your implementation into a .cpp file (and not expose it), gives you the same performance as doing it with std::vector<T> const& and probably the same implementation, avoids duplicating code, and uses light weight contiguous buffer type erasure (which is full of tasty keywords).

If the key point is that you want to access a continuous area in memory where instances of a specific char type are stored then you could define your function as

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

to make it clear that you assume they must be adjacent in memory.

Then for example to pass the content of a vector the code is simply

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

and for a string

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

or

myfunc(buffer, n);

for an array.

You can't directly typecast a std::vector to a std::string or vice versa. But using the iterators that STL containers provide does allow you to iterate both a vector and a string in the same way. And if your function requires random access of the container in question then either would 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 those last two function calls would print the same thing.

Now if you wanted to write a generic version that parsed only characters only stored in a string or in a vector you could write something that iterated 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 would do the same thing 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 multiple ways to solve a problem. Depending on what you have available any number of solutions might work. Try both and see which works better for your application. If you don't know the iterator type then the char typed array iteration is useful. If you know you will always have the template type to pass in then the template iterator method might be more useful.

The way your question is put at the moment is a bit confusing. If you mean to be asking "is it safe to cast a std::vector type to a std::string type or vice versa if the vector happens to contain char values of the appropriate type?", the answer is: no way, don't even think about it! If you're asking: "can I access the contiguous memory of non-empty sequences of char type if they're of the type std::vector or std::string ?" then the answer is, yes you can (with the data() member function).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM