2017-03-19 56 views
2

我有这样的代码(大约)在CPP的应用程序:为什么这会使用std ::的变换原因EXC_BAD_ACCESS

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显示这两种用法。为什么我的情况是错的?

回答

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与转换的结果。

+0

'assets.begin()因此等于assets.end()'这是我错过的那篇文章。谢谢! – Daenyth

0

std::transform()假定它可以直接写入输出。你的情况是一个零大小的矢量。您可以通过将矢量显式调整为变换输入的大小来修复该错误,或​​者使用已发现的back_inserter来修复该错误。

0

如果将assets的大小调整为与transform之前的rawAssets相同的大小,则不会导致访问不良。使用back_insert_iterator会导致push_back针对transform的每个迭代器被调用。如果没有,它会尝试访问assets的第一个,第二个,第三个等元素,该元素仍然为空,因此导致访问错误。

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()会为您提供结束迭代器值,然后代码继续愉快地写入向量末尾,然后废弃自身。

你有两个基本的选择:

  1. 获得begin()迭代器之前,resize()矢量到你即将transform()元素的数量,所以transform()最终填写预先调整数组的内容,确切地说。但是,由于您的数据来自列表,因此不易获得,因此:

  2. std::back_insert_iterator传递给transform(),而不是迭代器到空数组。

相关问题