将 std::string 解释为 char_type 的 std::vector?
Interpret a std::string as a std::vector of char_type?
我有一个接受 const vector<T>&
的 template<typename T>
函数。在上述函数中,我有向量 cbegin()
、cend()
、size()
和 operator[]
。
据我了解,string
和 vector
都使用连续的 space,所以我想知道我是否可以以一种优雅的方式为两种数据类型重用该函数。
能否将 std::string
重新解释为(适当的)char_type 的 std::vector
?如果可以,限制是什么?
如果您只为类型 const T&
创建模板并使用 begin()
、end()
等矢量和字符串共享的函数,那么您的代码将适用于这两种类型.
不保证 string
和 vector
的布局相同。它们在理论上可能是,但它们可能不在任何常见的实现中。因此,您不能安全地执行此操作。请参阅 Zan 的回答以获得更好的解决方案。
让我解释一下:如果我是标准库实现者并决定像这样实现 std::string....
template ...
class basic_string {
public:
...
private:
CharT* mData;
size_t mSize;
};
并决定像这样实施 std::vector...
template ...
class vector {
public:
...
private:
T* mEnd;
T* mBegin;
};
当您 reinterpret_cast<string*>(&myVector)
时,您最终会将指向数据末尾的指针解释为指向数据开头的指针,而将指向数据开头的指针解释为数据大小。如果成员之间的填充不同,或者有额外的成员,它可能会变得更奇怪,更破烂。
所以,是的,为了使其可能起作用,它们都需要存储连续的数据,但它们还需要相当多的其他实现才能使其起作用。
采用 STL 方式并使用迭代器。接受迭代器开始和迭代器结束。它将适用于所有可能的容器,包括像流这样的非容器。
您不能直接将 std::vector 类型转换为 std::string,反之亦然。但是使用 STL 容器提供的迭代器确实允许您以相同的方式迭代向量和字符串。如果您的函数需要随机访问相关容器,那么两者都可以。
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());
最后两个函数调用都会打印相同的内容。
现在,如果您想编写一个仅解析仅存储在字符串或向量中的字符的通用版本,您可以编写迭代内部数组的内容。
void array_function(const char * array, unsigned length)
{
for(unsigned i = 0; i < length; ++i)
{
std::cout << array[i] << std::endl;
}
}
在以下情况下,这两个函数会做同样的事情。
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());
总是有多种方法可以解决一个问题。根据您可用的内容,可能有多种解决方案。尝试两者,看看哪种更适合您的应用程序。如果您不知道迭代器类型,那么 char 类型的数组迭代很有用。如果您知道您将始终要传递模板类型,那么模板迭代器方法可能更有用。
如果关键点是您想要访问内存中存储特定 char 类型实例的连续区域,那么您可以将函数定义为
void myfunc(const CType *p, int size) {
...
}
明确表示您假设它们在内存中必须相邻。
然后例如传递向量的内容,代码很简单
myfunc(&myvect[0], myvect.size());
对于字符串
myfunc(mystr.data(), mystr.size());
或
myfunc(buffer, n);
对于数组。
std::experimental::array_view<const char>
n4512 表示连续的字符缓冲区。
写 ,它解决了这个问题,并且(根据我的经验)更多。
字符串和向量都与数组视图兼容。
这让您可以将您的实现移动到 .cpp
文件中(而不是公开它),为您提供与 std::vector<T> const&
相同的性能,并且可能是相同的实现,避免重复代码,并使用轻量级连续缓冲区类型擦除(充满美味关键字)。
你现在提出问题的方式有点混乱。如果你的意思是问"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?",答案是:不行,想都别想!如果你问:"can I access the contiguous memory of non-empty sequences of char type if they're of the type std::vector
or std::string
?" 那么答案是,可以(使用 data()
成员函数)。
我有一个接受 const vector<T>&
的 template<typename T>
函数。在上述函数中,我有向量 cbegin()
、cend()
、size()
和 operator[]
。
据我了解,string
和 vector
都使用连续的 space,所以我想知道我是否可以以一种优雅的方式为两种数据类型重用该函数。
能否将 std::string
重新解释为(适当的)char_type 的 std::vector
?如果可以,限制是什么?
如果您只为类型 const T&
创建模板并使用 begin()
、end()
等矢量和字符串共享的函数,那么您的代码将适用于这两种类型.
不保证 string
和 vector
的布局相同。它们在理论上可能是,但它们可能不在任何常见的实现中。因此,您不能安全地执行此操作。请参阅 Zan 的回答以获得更好的解决方案。
让我解释一下:如果我是标准库实现者并决定像这样实现 std::string....
template ...
class basic_string {
public:
...
private:
CharT* mData;
size_t mSize;
};
并决定像这样实施 std::vector...
template ...
class vector {
public:
...
private:
T* mEnd;
T* mBegin;
};
当您 reinterpret_cast<string*>(&myVector)
时,您最终会将指向数据末尾的指针解释为指向数据开头的指针,而将指向数据开头的指针解释为数据大小。如果成员之间的填充不同,或者有额外的成员,它可能会变得更奇怪,更破烂。
所以,是的,为了使其可能起作用,它们都需要存储连续的数据,但它们还需要相当多的其他实现才能使其起作用。
采用 STL 方式并使用迭代器。接受迭代器开始和迭代器结束。它将适用于所有可能的容器,包括像流这样的非容器。
您不能直接将 std::vector 类型转换为 std::string,反之亦然。但是使用 STL 容器提供的迭代器确实允许您以相同的方式迭代向量和字符串。如果您的函数需要随机访问相关容器,那么两者都可以。
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());
最后两个函数调用都会打印相同的内容。
现在,如果您想编写一个仅解析仅存储在字符串或向量中的字符的通用版本,您可以编写迭代内部数组的内容。
void array_function(const char * array, unsigned length)
{
for(unsigned i = 0; i < length; ++i)
{
std::cout << array[i] << std::endl;
}
}
在以下情况下,这两个函数会做同样的事情。
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());
总是有多种方法可以解决一个问题。根据您可用的内容,可能有多种解决方案。尝试两者,看看哪种更适合您的应用程序。如果您不知道迭代器类型,那么 char 类型的数组迭代很有用。如果您知道您将始终要传递模板类型,那么模板迭代器方法可能更有用。
如果关键点是您想要访问内存中存储特定 char 类型实例的连续区域,那么您可以将函数定义为
void myfunc(const CType *p, int size) {
...
}
明确表示您假设它们在内存中必须相邻。
然后例如传递向量的内容,代码很简单
myfunc(&myvect[0], myvect.size());
对于字符串
myfunc(mystr.data(), mystr.size());
或
myfunc(buffer, n);
对于数组。
std::experimental::array_view<const char>
n4512 表示连续的字符缓冲区。
写
字符串和向量都与数组视图兼容。
这让您可以将您的实现移动到 .cpp
文件中(而不是公开它),为您提供与 std::vector<T> const&
相同的性能,并且可能是相同的实现,避免重复代码,并使用轻量级连续缓冲区类型擦除(充满美味关键字)。
你现在提出问题的方式有点混乱。如果你的意思是问"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?",答案是:不行,想都别想!如果你问:"can I access the contiguous memory of non-empty sequences of char type if they're of the type std::vector
or std::string
?" 那么答案是,可以(使用 data()
成员函数)。