我在cpp app中大致有这段代码:
QList<Foo> rawAssets = getlist();
QVector<std::pair<QString, QString>> assets;
std::transform(rawAssets.begin(), rawAssets.end(), assets.begin(), makePair);
当我再次使用exc_bad_access
时,会导致assets
投掷。
但是,如果我将assets.begin()
更改为std::back_inserter(assets)
,那么它会按照我的预期运作。
我找到了std::transform
的教程,展示了两种用法。为什么我的情况不对?
答案 0 :(得分:3)
因为您刚刚宣布QVector<std::pair<QString, QString>> assets
;它的为空。 assets.begin()
因此等于assets.end()
,并指向空矢量的末尾。
std::transform
的第三个参数是一个迭代器,transform
将写转换结果(并在每次写入后递增)。
当你传入assets.begin()
时,transform
将通过这个过去的迭代器进行写入,从而导致越界写入。它与执行char x[3]; x[4] = 'a';
当您传入std::back_inserter(assets)
时,您创建了一个特殊的迭代器,以便通过它实际写入将写入的元素插入assets
。一切都很好。
如果assets
已经足够大,并且您希望覆盖其中的元素,则可以使用第一个表单。如果您希望扩展 assets
并使用转换结果,则使用第二种形式。
答案 1 :(得分:1)
assets
以空矢量开头。
transform()
的第三个参数是输出迭代器。您的代码基本上等同于以下内容:
QVector<std::pair<QString, QString>> assets;
auto output_iter=assets.begin();
// You now call transform(), passing output_iter
//
// transform() then essentially does the following:
*output_iter++ = /* first transform()ed value */;
*output_iter++ = /* second transform()ed value */;
// ... and so on.
这就是transform()
的工作方式。由于assets()
是一个空向量,begin()
为你提供了结束迭代器值,然后代码继续快速地写过向量的末尾,然后把它自己废弃。
您有两个基本选项:
在获取begin()
迭代器之前,resize()
向量为transform()
元素的数量,因此transform()
最终会填写一个完全预先调整数组的内容。但是,由于您的数据来自列表,因此不容易获得,因此:
将std::back_insert_iterator传递给transform()
,而不是将迭代器传递给空数组。
答案 2 :(得分:0)
std::transform()
假设它可以直接写入输出。在您的情况下,这是一个零大小的向量。您可以通过将矢量显式调整为变换输入的大小,或者使用已发现的back_inserter
来修复错误。
答案 3 :(得分:0)
如果您在assets
之前将rawAssets
调整为与transform
相同的尺寸,则不会导致访问权限错误。使用back_insert_iterator
导致为push_back
的每个迭代器调用transform
。没有它,它会尝试访问assets
的第一个,第二个,第三个等元素,它仍然是空的,因此导致访问不良。