为什么const_iterator不能提供类似于reverse_iterator的碱基
Why const_iterator does not provide a base like reverse_iterator?
为什么const_iterator
不提供const_iterator::base()
函数,像reverse_iterator
一样获得相应的非常量iterator
?
考虑以下伪代码(比如几何算法):
std::container< point > universe;
auto it = std::cbegin(universe);
std::list< decltype(it) > interesting_subset = sieve(it, std::cend(universe));
auto structure = algorithm(interesting_subset);
其中CCD_ 5是所有的输入点。在sieve()
之后,interesting_subset
包含到universe
的成员的子集的迭代器。下面的algorithm()
从interesting_subset
构造一个结果structure
,它由对universe
成员的引用(迭代器)组成。
最后,我想更改point
s,将其包含到生成的structure
中(比如,将它们移位)。但同样,我想保护它们在algorithm
作用期间不发生变形,因此我使用std::cbegin
/std::cend
,与std::begin
/std::end
相反。最后,我只有const_iterator
对源point
的引用。
这是iterator std::container< T >::const_iterator::base() const
成员函数的一个非常好的用例,我想将其呈现在STL容器中。
为什么const_iterator不提供const_iterator::base()函数,像reverse_iterator那样获得相应的非const迭代器?
维护施工安全。正如这里已经详细讨论过的那样,提供这种功能将是非常危险的。
最后,我想改变点,包含到结果结构中(比如,移动它们)。但同样,我想在算法操作过程中保护它们不被修改,因此我使用std::cbegin/std::cend作为std::begin/std::end的反面。最后,我只有对源点的const_iterator引用。
好吧,你要求base
成员做错事。当然,这会解决你的问题,但正如所说,这太危险了。让我再问你一个问题:
如果我对一个对象有一个
const_iterator
,并且对容器有非常量访问权限,那么我如何有效地(在恒定时间内)获得对引用对象的iterator
?
这里有一个奇特的技巧:
template <typename Container, typename ConstIterator>
typename Container::iterator remove_constness(Container& c, ConstIterator it)
{
return c.erase(it, it);
}
我不认为这个把戏有任何功劳。我是从https://stackoverflow.com/a/10669041/2079303他们称赞霍华德·欣南特和乔恩·卡尔布
正如该答案的评论中所讨论的,这个技巧适用于所有标准容器,但不一定适用于所有可能符合标准的第三方容器,因为它们不需要提供erase
。
就我个人而言,我更希望标准容器有一个非常量成员函数,可以将给定的const_iterator
转换为iterator
,但它们没有,所以你需要解决它。
因为没有从const T*
到T*
的转换:常量正确性。
与reverse_iterator
的比较是无效的,因为"反向迭代器"answers"正向迭代器)之间的区别与"常量迭代器(constiterator)"answers"非常量迭代者(nonconstiterater)"之间的区别完全正交。后者具有影响;前者最终不会。
reverse_iterator
不会改变底层对象是否为const,const_iterator与迭代器无关(除了可转换和引用的要求),因此您比较的是apple和orange。
如果const_iterator
确实可以通过base
提供对非常量迭代器的访问,那么就有可能执行之类的操作
auto const & a = std::vector<int>(20, 1);
auto it = std::cbegin(a);
*it.base() = 4;
标准允许这样做。
原则上,您确实希望规避const_iterator
提供的防修改保护。但这就是const_iterator
的意义所在。因此,我认为(并希望)这既不是一个好主意,也不太可能发生。
尽管我认为这是一个XY问题,但我回答了这个问题,而不是提供如何正确处理的指导。
-编辑-
如果您希望const_iterator
能够返回iterator
,那么您需要的是iterator
。
你的意图似乎是
- 将
const_iterator
传递到sieve
,其中不允许sieve
更改元素 - 将相同的迭代器传递给
algorithm
,使其可以修改它们
同一个对象需要两个不同的东西。没有人阻止sieve
的实现者使用it.base()
,因此根本不能保证sieve
不会更改元素。我重复一遍,这就是const_iterator
问题的要点。
如果有任何方法可以使用const_iterator
来改变事物,它只会破坏它们。
这是一个有趣的问题。您希望能够在对这些点进行推理时保护它们,但在对它们进行推理后返回对它们的可变引用。
作为对这些点进行推理的结果,您实际返回的是它们的"名称"或"标识符"。
我们可以想象通过名称映射它们,并得到sieve()
来返回相关名称的向量。如果我们想避免存储正式名称(唯一数字、文本字符串等)的开销,这样的名称可以只是一个地址。
如果我们使用const对象的地址作为名称,那么当然要将其转换回对可变对象的引用,我们需要universe
0。这可能被视为我们合理使用const强制转换的少数几次之一。在这样做的时候,我们应该将它封装在一个实用程序类中,以限制任何后果。
编辑:重新思考解决方案。现在,不守规矩的客户端代码无法滥用此代码。
#include <iostream>
#include <vector>
struct point { int x, y; };
inline std::ostream& operator<<(std::ostream& os, const point& p)
{
os << "(" << p.x << ", " << p.y << " )";
return os;
}
struct point_collection
{
using container_type = std::vector<point>;
point_collection(container_type points) : _points(std::move(points)) {}
using const_iterator = const point*;
using iterator = point*;
const_iterator begin() const { return &*_points.begin(); }
const_iterator end() const { return &*_points.end(); }
// note that this function is only available on a non-const point_collection
point& mutable_reference(const_iterator input)
{
// could put an assert in here to ensure that input is within our range
return *const_cast<iterator>(input);
}
container_type _points;
};
std::vector<point_collection::const_iterator> sieve(point_collection::const_iterator first,
point_collection::const_iterator last)
{
std::vector<point_collection::const_iterator> result;
for ( ; first != last ; ++first )
{
if (first->x > 6)
result.push_back(first);
}
return result;
}
point_collection make_a_universe()
{
return {
std::vector<point> {
{ 10, 10 },
{ 6, 6 }
}
};
}
auto main() -> int
{
using namespace std;
auto universe = make_a_universe();
auto interesting = sieve(universe.begin(), universe.end());
for (auto point_id : interesting) {
auto& p = universe.mutable_reference(point_id);
p.x = -p.x;
cout << p << endl;
}
return 0;
}
预期输出:
(-10, 10 )
- 错误:未在此范围内声明'reverse'
- 在调试模式下引发C++ "deque iterator not dereferencable"异常
- std::iterator::reference 必须是引用吗?
- 为什么unordered_set<string::iterator>不起作用?
- 造成致命错误:boost/fusion/iterator/equal_to.hpp 没有这样的文件或目录
- Visual accept std::string from std::byte iterator
- 使用to_string、reverse、stoi组合的C++反转编号给出运行时错误实例超出范围
- 什么是"std::set<int,int>::iterator"?
- 从 std::vector 中删除项目时"Iterator not incrementable"
- 如何从 boost::container::vector<std::string>::iterator 访问索引和对象?
- 空集"Out of bound iterator"
- 如何使用set<pair<int,int> >::iterator itrator it迭代set<pair<int,int> >st中的值?
- "How to make a recursive call for palindrom numbers without reverse function in c++?"
- 给定一个类型为 Container:<T>:Iterator 的函数参数,如何为某些类型的 T 实现特定的重载?
- 带升压async_read_some "String iterator not dereferncable"
- C++为什么"deque iterator not dereferencable "
- 错误:与'operator='不匹配(操作数类型为"std::map<int、double>::iterator
- 自动,错误:MAP ITERATOR没有名为“ First”的成员
- set<shared_ptr<T>>::iterator to set<shared_ptr<t const>>::const_iterator
- 标准::复制失败,"cannot seek vector iterator after end"