【发布时间】:2017-08-23 22:14:02
【问题描述】:
我有一个包含 n 个字符串的向量。现在假设我想在地图中“分页”或“分组”这些字符串。
typedef std::vector<std::string> TStringVec;
TStringVec myVec;
//.. fill myVecwith n elements
typedef std::map<int, TStringVec>> TPagedMap;
TPagedMap myMap;
int ItemsPerPage = 3 // or whatever
int PagesRequired = std::ceil(myVec.size() / nItemsPerPage);
for (int Page = 0; Page < NumPagesMax; ++Page)
{
TStringVec::const_iterator Begin = myVec.begin() + (ItemsPerPage * Page);
TStringVec::const_iterator End = myVec.begin() + ItemsPerPage * (Page+1);
myMap[Page] = TStringVec(Begin, End);
}
在这里很容易发现问题。在确定结束迭代器时,我冒着将分配的空间留给向量的风险。
简单示例:向量中有 5 个元素,ItemsPerPage 为 3。这意味着我们需要在地图中总共 2 个页面来对所有元素进行分组。
现在在进行最后一次迭代时,begin 指向 myVec[3],而 end 则“指向”myVec[6]。请记住,myVec 只有 5 个元素。
这种情况可以通过交换安全处理吗
TStringVec::const_iterator End = myVec.begin() + ItemsPerPage * (Page+1);
与
TStringVec::const_iterator End = std::min(myVec.begin() + ItemsPerPage * (Page+1), myVec.end());
它当然可以编译,而且它似乎可以工作。但我不确定这是否可以被认为是安全的事情。有什么建议或明确的答案吗?
我认为问题是......“过去”的值 .end() 是否保证大于 .end() 返回的地址?
提前致谢。
编辑:当然,事先检查if 可以解决问题,但我正在寻找更优雅 的解决方案。
【问题讨论】:
-
为什么要遍历页面,计算
Begin和End?为什么不遍历字符串,计算Page? -
嗯,你也会有同样的问题,不是吗?
-
不,因为您可以毫无危险地将页面添加到地图中。
-
那我不明白你的意思……
-
如果您遍历页面并计算
Begin和End,您可能会取消引用超过向量末尾的指针,即UB。如果您遍历字符串并计算页面,则无法越过向量的末尾,并且您可以将页面添加到地图中而不会越过地图的末尾。