Есть ли способ найти контейнер, на который указывает итератор? В частности, я хочу иметь возможность найти std::vector, на который указывает конкретный std::vector::iterator, чтобы я мог проверить диапазон, без необходимости фактически передавать ссылки на этот вектор.
Если (как я подозреваю) ответ отрицательный, почему бы и нет?
edit: спасибо за несколько быстрых и (в основном) точных ответов. Эван Теран прибивает. Об оптимизации я вообще не думал, но теперь это очевидно.
Несколько человек спросили, для чего я хочу это сделать. Ничего особо важного. У меня есть объект, который инициализируется вектором и итератором, указывающим на вектор. Было бы мило и удобно, если бы я мог инициализировать объект только с помощью итератора, потому что тогда я мог бы преобразовать vector::iterator непосредственно в этот объект (это звучит странно, но имеет смысл в конкретном случае). Но это совсем не критично.





Я так не верю. Если бы итераторам приходилось хранить ссылку / указатель на свой контейнер, то для них было бы невозможно оптимизировать до облегченного указателя (что можно сделать с контейнерами, гарантирующими непрерывное хранилище, такое как векторы и т. д.).
Я не верю, что есть какой-то открытый способ сделать это. Причина в том, что итератор не в этом. Конечно, нет никакой технической причины, по которой итератор не мог удерживать указатель на свой родительский контейнер. Даже если он реализован таким образом, что не требует этого указателя, он все равно может его удерживать.
Итераторы предназначены для перебора коллекции и, как таковые, предоставляют интерфейс, необходимый для этого и только этого. Это хорошие принципы объектно-ориентированного программирования.
Могу я спросить, каков ваш вариант использования, что вам нужно знать «диапазон» контейнера с итератором?
Вы не можете получить контейнер из итератора обычным способом. В качестве примера того, почему простой указатель можно использовать в качестве итератора:
#include <algorithm>
#include <cstdio>
#include <cstring>
int
main(int argc, char *argv[])
{
const char s[] = "Hello, world!";
const char *begin = s;
const char *end = s + strlen(s);
std::for_each(begin, end, putchar);
return 0;
}
Как можно получить исходную строку из указателя (если он не указан в начале строки)?
Однако, если вам нужна эта функция, вы всегда можете осуществлять свою собственную оболочку вокруг итератора, хранящего ссылку на контейнер.
Но это не совсем «почему», это во многом философский вопрос. Однако он действительно иллюстрирует техническую / дизайнерскую проблему, которая могла бы возникнуть, если бы итераторы гипотетически задумывались как нечто иное.
Теоретически есть способ, если рассматриваемый итератор является хотя бы прямым итератором. Вы можете проверить, является ли ваш итератор одним из итераторов в [first, last) для каждого контейнера-кандидата. Поскольку вы используете векторный контейнер, у вас есть итератор с произвольным доступом, вы можете использовать оператор «меньше», чтобы быстро выполнить эту проверку.
Вам НЕОБХОДИМО знать все векторы-кандидаты, чтобы проверить их заранее, и это не общий способ получить контейнер, которому принадлежит итератор.
Однако вы можете определить расширение итераторов произвольного доступа, украсив итератор произвольного доступа чем-то, что содержит указатель на создающий вектор. Скорее всего, это будет немного неэлегантно, неэффективно и неудобно. Так что сначала посмотрите, сможете ли вы переписать код, чтобы избежать этой необходимости.
Это первое предложение определенно опирается на неустановленные детали реализации, и его будет очень сложно поддерживать. Я бы предпочел реализовать декоратор; по крайней мере, тогда он гарантированно будет работать всегда и сделает мои намерения очевидными.
Неправильно. Первое предложение основывается либо на итераторах проверки равенства возможностей, которые официально поддерживаются, либо на возможности <проверять итераторы произвольного доступа, которые официально поддерживаются. Никакого взлома не найти. Пожалуйста, прочтите stldoc.
Я бы хотел отказаться от своего предыдущего комментария, но оставляю его для потомков. Фактически, решение действительно потребовало бы использования итераторов с произвольным доступом, которые в основном были бы реализованы как указатели или что-то вроде указателей, включающих местоположения в адресном пространстве (согласно техническому определению «адресного пространства»). Я не вижу четкого стандартизованного определения того, что произойдет, если вы сравните итераторы произвольного доступа, возникающие из разных контейнеров.
STL этого не допускает.
Итераторы Vecor, например, могут быть реализованы просто как указатель. И не существует общего способа получить объект из указателя, указывающего на некоторые данные, которые он выделил.
Как было предложено ранее, лучше всего переписать код так, чтобы вам не требовалось такое поведение. Это то же самое, что держать монету, но вы не знаете, откуда она взялась, если не отметили это на бумаге.
Если вы не можете переписать код, вы все равно можете ввести объект-оболочку, который содержит указатель на контейнер и сам итератор. Для чего это вам конкретно нужно?
Нет никакого способа заставить это работать. Причина проста: добавление к итераторам способа получить контейнер, на который они указывают, - это
Вы говорите, что вам это нужно для проверки диапазона. Вы можете предоставить конечный итератор, который будет указывать на одну после последней допустимой позиции итератора в диапазоне. Проверьте, не находится ли ваша текущая позиция в конце. Это все, что вам нужно сделать для проверки диапазона.
Он демонстрирует, почему вы не можете получить контейнер из итерации, на конкретном и простом примере ...