Поиск владельца итератора STL

Есть ли способ найти контейнер, на который указывает итератор? В частности, я хочу иметь возможность найти std::vector, на который указывает конкретный std::vector::iterator, чтобы я мог проверить диапазон без необходимости фактически передавать ссылки на этот вектор.

Если (как я подозреваю) ответ отрицательный, то почему бы и нет?

edit: спасибо за ряд быстрых и (в основном) точных ответов. Эван Теран прибивает это. Я вообще не думал об оптимизации, но теперь это очевидно.

Несколько человек спросили, для чего я хочу это сделать. Ничего особенно важного. У меня есть объект, который инициализируется вектором и итератором, указывающим на вектор. Было бы мило и удобно, если бы я мог инициализировать объект только с помощью итератора, потому что тогда я мог бы преобразовать vector::iterators непосредственно в этот объект (это звучит странно, но в конкретном случае имеет смысл). Но это совсем не принципиально.


person Tom Smith    schedule 17.12.2008    source источник


Ответы (7)


Я так не думаю. Если бы итераторам приходилось хранить ссылку/указатель на свой собственный контейнер, то было бы невозможно оптимизировать их до облегченного указателя (что можно сделать с контейнерами, гарантирующими непрерывное хранение, такое как векторы и тому подобное).

person Evan Teran    schedule 17.12.2008

Невозможно заставить это работать. Причина проста: добавление к итераторам способа получения контейнера, на который они указывают,

  • Бессмысленно. Итераторы перебирают коллекцию. Как говорили другие, только это, не более того.
  • Несовместимо с требованиями к итератору. Помните, что указатель — это итератор произвольного доступа. Помещение указателя контейнера в итератор было бы бесполезно для алгоритмов, поскольку они должны быть универсальными, отделенными от конкретных реализаций итератора. Указатель, используемый в качестве итератора, не может иметь указатель на массив, из которого он был взят в качестве члена.

Вы говорите, что вам это нужно для проверки диапазона. Вы можете указать конечный итератор, который указывает на одну позицию после последней действительной позиции итератора диапазона. Проверьте, не находится ли ваша текущая позиция в конце. Это все, что вам нужно сделать для проверки диапазона.

person Johannes Schaub - litb    schedule 17.12.2008

Вы не можете получить контейнер из итератора обычным способом. Например, в качестве итератора можно использовать простой указатель:

#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;
}

Как вы могли бы получить исходную строку из указателя (если он не указан в начале строки)?

Однако, если вам нужна эта функциональность, вы всегда можете реализуйте свою собственную оболочку вокруг итератора, которая хранит ссылку на контейнер.

person Judge Maygarden    schedule 17.12.2008
comment
Это демонстрирует, почему вы не можете получить контейнер из итерации, на конкретном и простом примере... - person Judge Maygarden; 18.12.2008
comment
Но на самом деле это не «почему», «почему» в значительной степени философское. Однако это иллюстрирует техническую/проектную проблему, которая возникла бы, если бы итераторы гипотетически предназначались для чего-то другого. - person Lightness Races in Orbit; 23.10.2018

Теоретически есть способ, если рассматриваемый итератор является по крайней мере прямым итератором. Вы можете проверить, является ли ваш итератор одним из итераторов в [first,last) для каждого контейнера-кандидата. Поскольку вы используете векторный контейнер, у вас есть итератор с произвольным доступом, вы можете использовать оператор «меньше», чтобы быстро выполнить эту проверку.

Вам ДЕЙСТВИТЕЛЬНО нужно знать все векторы-кандидаты, по которым нужно проверить заранее, и это не общий способ получить контейнер, к которому принадлежит итератор.

Однако вы можете определить расширение итераторов произвольного доступа, украсив итератор произвольного доступа чем-то, содержащим указатель на создающий вектор. Это, вероятно, будет немного неэлегантным, неэффективным и неудобным. Поэтому сначала посмотрите, можете ли вы переписать код, чтобы избежать этой необходимости.

person Thomas Kammeyer    schedule 17.12.2008
comment
Это первое предложение определенно основано на неустановленных деталях реализации и будет очень хакерским в обслуживании. Я бы предпочел реализовать декоратор; по крайней мере, тогда это гарантированно всегда работает и делает мои намерения очевидными. - person jdmichal; 17.12.2008
comment
Неправильно. Первое предложение основывается либо на возможности итераторов проверки на равенство, которая официально поддерживается, либо на возможности ‹ проверки итераторов произвольного доступа, которая официально поддерживается. Не взломать, чтобы быть найденным. Пожалуйста, прочтите stldoc. - person Thomas Kammeyer; 17.12.2008
comment
Я хотел бы отозвать свой предыдущий комментарий, но я оставляю его для потомков. Фактически, решение действительно потребовало бы опоры на итераторы произвольного доступа, которые в основном реализованы как указатели или что-то вроде указателей, включающих местоположения в адресном пространстве (согласно техническому определению адресного пространства). Я не вижу четкого стандартизированного определения того, что происходит, если сравнивать итераторы произвольного доступа, возникающие из разных контейнеров. - person Thomas Kammeyer; 29.11.2016

STL этого не позволяет.

Итераторы Vecor, например, могут быть реализованы просто как указатель. И нет общего способа получить объект из указателя, указывающего на некоторые данные, выделенные объектом.

person Drew Dormann    schedule 17.12.2008

Я не верю, что есть открытый способ сделать это. Причина в том, что это не цель итератора. Конечно, нет никаких технических причин, по которым итератор не может содержать указатель на родительский контейнер. Даже если он реализован таким образом, что не требует этого указателя, он все равно может его удерживать.

Итераторы предназначены для перебора коллекции, и поэтому они предоставляют интерфейс, необходимый для этого и только для этого. Это хорошие принципы объектно-ориентированного программирования.

Могу я спросить, каков ваш вариант использования, что вам нужно знать «диапазон» контейнера с итератором?

person jdmichal    schedule 17.12.2008

Как было предложено ранее, лучше всего переписать свой код, чтобы вам не требовалось такое поведение. Это то же самое, что держать монету, но вы понятия не имеете, откуда она взялась, если только не записали это на бумаге.

Если вы не можете переписать код, вы все равно можете ввести объект-оболочку, содержащий указатель на контейнер и сам итератор. Для чего конкретно вам это нужно?

person Tamara Wijsman    schedule 17.12.2008