我在从字符串创建矢量时遇到问题。有人可以解释下面4例之间的区别吗?根据{{3}}我的预期Case 1
与Case 2
的工作方式相同,但同样奇怪的原因,但它没有。
typedef std::vector<uint8_t> uint8vec_t;
std::string keySecret ()
{
return std::string ("SomeSecret");
}
案例1
// throws std::bad_alloc
uint8vec_t vSecret (keySecret ().begin (), keySecret ().end ());
案例2
// results in a vector with strange length
uint8vec_t vSecret (keySecret ().begin (), keySecret ().begin () + keySecret ().length ());
案例3
// throws std::bad_alloc
uint8vec_t vSecret (&keySecret ()[0], &keySecret ()[keySecret ().length ()]);
案例4
// throws std::bad_alloc
uint8vec_t vSecret (&keySecret ()[0], &keySecret ()[0] + keySecret ().length ());
答案 0 :(得分:7)
他们都很糟糕,你恰好在第二种情况下得到了正确的行为。问题是keySecret
每次都返回一个不同的std::string
对象。您无法在其中一个上调用begin
而在另一个上调用end
,并希望它们以任何方式相关。
您应该拨打keySecret
一次,制作本地副本,然后在该单个本地对象上调用begin
和end
。
答案 1 :(得分:3)
在对keySecret()
的两次调用之后,你在内存中有两个不同的字符串:
...x..x....SomeSecret\0..x.x.x...x..x..x.x...SomeSecret\0....x.x..x.x..
^ ^ ^ ^
begin1 end1 begin2 end2
然后您尝试使用
创建矢量vector<char> v(begin1, end2);
或
vector<char> v(begin2, end1);
(取决于哪个字符串恰好在内存中较早,哪些字符串由keySecret()
调用返回。)
第一个将分配end2 - begin1
个字节并将"SomeSecret\0..x.x.x...x..x..x.x...SomeSecret\0"
复制到该内存中,两个迭代器之间有一些任意数量的字节,包含字符串之间内存中发生的任何内容。这是未定义的行为,因为读取超过为第一个字符串分配的内存的末尾。
第二个将尝试找到负值的距离end1 - begin2
,因此包装到一个非常大的无符号数,并尝试分配那么多字节失败,抛出bad_alloc
异常。
在这两种情况下,对指向不同对象的两个不相关指针执行指针运算是未定义的行为,因此理论上任何事情都可能发生。在实践中,结果可以相当逻辑地解释,如上所述(尽管对于第一种情况而言,段错误不会是令人惊讶的结果,而不是具有错误内容的向量)。