字符串到向量转换抛出std :: bad_alloc

时间:2014-11-25 14:29:39

标签: c++ string vector std

我在从字符串创建矢量时遇到问题。有人可以解释下面4例之间的区别吗?根据{{​​3}}我的预期Case 1Case 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 ());

2 个答案:

答案 0 :(得分:7)

他们都很糟糕,你恰好在第二种情况下得到了正确的行为。问题是keySecret每次都返回一个不同的std::string对象。您无法在其中一个上调用begin而在另一个上调用end,并希望它们以任何方式相关。

您应该拨打keySecret一次,制作本地副本,然后在该单个本地对象上调用beginend

答案 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异常。

在这两种情况下,对指向不同对象的两个不相关指针执行指针运算是未定义的行为,因此理论上任何事情都可能发生。在实践中,结果可以相当逻辑地解释,如上所述(尽管对于第一种情况而言,段错误不会是令人惊讶的结果,而不是具有错误内容的向量)。