如何消除const_iterator的常量性?
作为这个问题的扩展const_iterators更快吗?,我还有另一个问题在const_iterators
上。 如何消除 const_iterator 的常量性? 尽管迭代器是指针的广义形式,但 const_iterator 和迭代器仍然是两个不同的东西。 因此,我相信,我也不能使用 const_cast<> 从 const_iterator 转换为迭代器。
一种方法是定义一个迭代器,它移动到 const_iterator
指向的元素。 但这看起来是一个线性时间算法。
您知道实现此目标的最佳方法是什么吗?
As an extension to this question Are const_iterators
faster?, I have another question on const_iterators
. How to remove constness of a const_iterator
?
Though iterators are generalised form of pointers but still const_iterator
and iterator
s are two different things. Hence, I believe, I also cannot use const_cast<>
to covert from const_iterator
to iterator
s.
One approach could be that you define an iterator which moves 'til the element to which const_iterator
points. But this looks to be a linear time algorithm.
Any idea on what is the best way to achieve this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
C++11 中有一个时间复杂度恒定的解决方案:对于任何序列、关联或无序关联容器(包括所有标准库容器),您可以使用空范围调用 range-erase 成员函数
: -erase 成员函数有一对 const_iterator 参数,但它们返回一个迭代器。 由于提供了空范围,因此对擦除的调用不会更改容器的内容。
向 Howard Hinnant 和 Jon Kalb 的这一技巧致敬。
There is a solution with constant time complexity in C++11: for any sequence, associative, or unordered associative container (including all of the Standard Library containers), you can call the range-erase member function with an empty range:
The range-erase member functions have a pair of
const_iterator
parameters, but they return aniterator
. Because an empty range is provided, the call to erase does not change the contents of the container.Hat tip to Howard Hinnant and Jon Kalb for this trick.
不幸的是,线性时间是执行此操作的唯一方法:
其中 iter 和 constIter 是合适的 typedef,而 d 是要迭代的容器。
Unfortunately linear time is the only way to do it:
where iter and constIter are suitable typedefs and d is the container over which you are iterating.
在您上一篇文章的答案中,有几个人(包括我)出于与性能无关的原因建议使用 const_iterators 。 从设计板到代码的可读性、可追溯性……使用 const_iterators 提供对非常量元素的变异访问比根本不使用 const_iterators 糟糕得多。 您正在将代码转换为只有您才能理解的东西,并且设计更糟糕,并且真正的可维护性痛苦。 仅仅使用 const 来抛弃它比根本不使用 const 更糟糕。
如果你确定你想要它,C++ 的好处/坏处是你总能找到足够的绳子来吊死自己。 如果您的目的是使用 const_iterator 来解决性能问题,那么您确实应该重新考虑它,但如果您仍然想大快朵颐……那么 C++ 可以提供您选择的武器。
首先,最简单的:如果您的操作将参数作为 const (即使内部应用 const_cast),我相信它应该直接在大多数实现中工作(即使它可能是未定义的行为)。
如果您无法更改函子,那么您可以从任一方面解决问题:在 const 迭代器周围提供一个非常量迭代器包装器,或者在非常量函子周围提供一个 const 函子包装器。
迭代器外观,漫长的道路:
In the answers to your previous post, there were a couple of people, me included, that recommended using const_iterators instead for non-performance related reasons. Readability, traceability from the design board to the code... Using const_iterators to provide mutating access to a non-const element is much worse than never using const_iterators at all. You are converting your code into something that only you will understand, with a worse design and a real maintainability pain. Using const just to cast it away is much worse than not using const at all.
If you are sure you want it, the good/bad part of C++ is that you can always get enough rope to hang yourself. If your intention is using const_iterator for performance issues, you should really rethink it, but if you still want to shoot your foot off... well C++ can provide your weapon of choice.
First, the simplest: if your operations take the arguments as const (even if internally apply const_cast) I believe it should work directly in most implementations (even if it is probably undefined behavior).
If you cannot change the functors, then you could tackle the problem from either side: provide a non-const iterator wrapper around the const iterators, or else provide a const functor wrapper around the non-const functors.
Iterator façade, the long road:
Scott Meyer 的文章关于优先使用迭代器而不是 const_iterators 回答了这个问题。 Visage 的答案是 C++11 之前唯一安全的替代方案,但实际上对于实现良好的随机访问迭代器来说是恒定时间,对于其他迭代器来说是线性时间。
Scott Meyer's article on preferring iterators over const_iterators answers this. Visage's answer is the only safe pre-C++11 alternative, but is actually constant time for well-implemented random access iterators, and linear time for others.
这可能不是您想要的答案,但有些相关。
我假设您想更改迭代器指向的内容。 我做的最简单的方法是 const_cast 返回的引用。
像这样的
const_cast(*it);
This may not be the answer you wanted, but somewhat related.
I assume you want to change the thing where the iterator points to. The simplest way I do is that const_cast the returned reference instead.
Something like this
const_cast<T&>(*it);
我相信设计良好的程序不需要这种转换。
如果您需要这样做 - 尝试重新设计代码。
作为解决方法,您可以使用以下方法:
但我认为有时这种转换是不可能的,因为您的算法无权访问容器。
I believe this conversion is not needed in a well-designed program.
If you need do this - try redesigning the code.
As workaround you can use the following:
But I think that sometimes this conversion is impossible, because your algorithms don't have access to the container.
您可以从 const_iterator 中减去 begin() 迭代器以获得 const_iterator 指向的位置,然后将 begin() 添加回该位置以获得非常量迭代器。 我认为这对于非线性容器来说不是非常有效,但对于诸如矢量之类的线性容器来说,这将花费恒定的时间。
编辑:这似乎仅适用于线性(随机访问)容器。
You can subtract the begin() iterator from the const_iterator to obtain the position the const_iterator is pointing to and then add begin() back to that to obtain a non-const iterator. I don't think this will be very efficient for non-linear containers, but for linear ones such as vector this will take constant time.
EDIT: This appears to only work for linear (random access) containers.
您可以将 const 迭代器值指针转换为非常量值指针并直接使用它,如下所示
you can convert your const iterator value pointer to a non const value pointer and use it directly something like this
我认为提出一个适用于不在标准库中并且不包含擦除()方法的容器的解决方案会很有趣。
尝试使用此选项会导致 Visual Studio 2013 在编译时挂起。 我没有包含测试用例,因为将其留给能够快速弄清楚界面的读者似乎是个好主意; 我不知道为什么这会在编译时挂起。 即使 const_iterator 等于 begin() 也会发生这种情况。
I thought it would be fun to come up with a solution to this that works for containers that aren't in the standard library and don't include the erase() method.
Attempting to use this causes Visual Studio 2013 to hang on compile. I'm not including the test case because leaving it to readers who can quickly figure out the interface seems like a good idea; I don't know why this hangs on compile. This occurs even when the const_iterator is equal to begin().
假设容器的 const_iterator 与其迭代器具有相同的布局(对于所有 STL 容器都是有效的假设),您可以简单地将前者位转换为后者:
Assuming your container's
const_iterator
has the same layout as itsiterator
(a valid assumption for all STL containers), you can simply bit-cast the former to the latter: