получить указатель из итератора
От: B0FEE664  
Дата: 06.12.22 18:00
Оценка: 2 (1)
Есть некий итератор стандартного контейнера, а из него надо получить указатель на объект этого контейнера.
Многие советуют использовать конструкцию вида:
ptr = &*it;
но для past-the-end итератора такая конструкция не валидна.

Вроде бы для past-the-end итератора можно использовать конструкцию вида:
ptr = it.operator->();
но у меня возникли сомнения...
Поэтому вопросы следующие:
Есть ли гарантия, что it.operator->() вернёт именно указатель, а не некий тип его имитирующий?
Верно ли, что если it — это past-the-end итератор, то результат it.operator->() — это past-the-end указатель? Или это зависит от типа контейнера?

Верно ли, что для пустого контейнера x, следующий код — это UB:
bool bEmpty = std::begin(x).operator->() == std::end(x).operator->()

? Или же есть гарантия, что для такого случая значения указателей устанавливаются в NULL и всё ok?
И каждый день — без права на ошибку...
Re: получить указатель из итератора
От: watchmaker  
Дата: 06.12.22 18:36
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Есть некий итератор стандартного контейнера, а из него надо получить указатель на объект этого контейнера.

BFE>Многие советуют использовать конструкцию вида:
BFE>ptr = &*it;

Вообще-то, std::addressof(*it). Так как operator& не обязан возвращать указатель, а даже если и возвращает, то не обязан возвращать его для элемента *it.

Только даже это не всегда имеет смысл: попробуй в пресловутом std::vector<bool> адрес элемента взять.

BFE>но для past-the-end итератора такая конструкция не валидна.


Верно.


BFE>Вроде бы для past-the-end итератора можно использовать конструкцию вида:

BFE>ptr = it.operator->();
Нельзя

BFE>Есть ли гарантия, что it.operator->() вернёт именно указатель, а не некий тип его имитирующий?

Нет.
В C++ специально сделали для opeator-> особые правила, для этого случая, чтобы можно было возвращать не указатели из opeator->, а компилятор потом их сам в цепочку вызовов выстраивал.

BFE>Верно ли, что для пустого контейнера x, следующий код — это UB:

BFE>bool bEmpty = std::begin(x).operator->() == std::end(x).operator->()

Для любого контейнера это UB.
Даже для std::basic_string формально не разрешено, хотя при этом str[str.size()] содержит нулевой символ, который можно читать.


Вообще, если собираешься с ассертами, то оно просто в библиотеке упадёт и всё
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/debug/safe_iterator.h#L314-L322
https://github.com/llvm-mirror/libcxx/blob/master/include/list#L367-L368
Ну или на аналогичной строке в твоей версии STL
Отредактировано 06.12.2022 19:49 watchmaker . Предыдущая версия .
Re[2]: получить указатель из итератора
От: B0FEE664  
Дата: 07.12.22 09:29
Оценка:
Здравствуйте, watchmaker, Вы писали:

BFE>>Вроде бы для past-the-end итератора можно использовать конструкцию вида:

BFE>>ptr = it.operator->();
W>Нельзя

Интересно, зачем так сделано? Ведь здесь нет разыменования.
И каждый день — без права на ошибку...
Re[2]: получить указатель из итератора
От: B0FEE664  
Дата: 07.12.22 14:40
Оценка:
W>Вообще-то, std::addressof(*it). Так как operator& не обязан возвращать указатель, а даже если и возвращает, то не обязан возвращать его для элемента *it.
W>Только даже это не всегда имеет смысл: попробуй в пресловутом std::vector<bool> адрес элемента взять.

Так как итераторы — это обобщённые абстрактные указатели, то я предлагаю добавить каждому итератору метод get() который возвращает указатель на его объект или past-the-end указатель для past-the-end итератора или nullptr для всех случаев, когда указатель не может быть получен.
Возражения?
И каждый день — без права на ошибку...
Re: получить указатель из итератора
От: Sm0ke Россия ksi
Дата: 07.12.22 18:14
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Есть некий итератор стандартного контейнера, а из него надо получить указатель на объект этого контейнера.

BFE>Многие советуют использовать конструкцию вида:
BFE>ptr = &*it;
BFE>но для past-the-end итератора такая конструкция не валидна.

BFE>Вроде бы для past-the-end итератора можно использовать конструкцию вида:

BFE>ptr = it.operator->();
BFE>но у меня возникли сомнения...
BFE>Поэтому вопросы следующие:
BFE>Есть ли гарантия, что it.operator->() вернёт именно указатель, а не некий тип его имитирующий?
BFE>Верно ли, что если it — это past-the-end итератор, то результат it.operator->() — это past-the-end указатель? Или это зависит от типа контейнера?

BFE>Верно ли, что для пустого контейнера x, следующий код — это UB:

BFE>
BFE>bool bEmpty = std::begin(x).operator->() == std::end(x).operator->()
BFE>

BFE>? Или же есть гарантия, что для такого случая значения указателей устанавливаются в NULL и всё ok?

1. Сперва надо проверять итератор на past-the-end.
2. У итератора может и не быть оператора стрелка.
3. Оператор * у итератора с iterator_category output_iterator_tag может возвращать ссылку. А может и прокси объект с оператором присвоения, как у vector<bool> ;
Следовательно взятие адреса после разыменования не всегда корректно. &*it не всегда можно делать.
Re: получить указатель из итератора
От: rg45 СССР  
Дата: 07.12.22 18:51
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Многие советуют использовать конструкцию вида:

BFE>ptr = &*it;
BFE>но для past-the-end итератора такая конструкция не валидна.

BFE>Вроде бы для past-the-end итератора можно использовать конструкцию вида:

BFE>ptr = it.operator->();

То есть, использовать it.operator*() нельзя, а it.operator->() можно? Как такое может быть?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: получить указатель из итератора
От: B0FEE664  
Дата: 07.12.22 22:26
Оценка:
Здравствуйте, rg45, Вы писали:

R>То есть, использовать it.operator*() нельзя, а it.operator->() можно? Как такое может быть?

В простом случае, когда iterator::pointer — это указатель, а iterator::reference — это ссылка,
вызов it.operator*() приводит к разыменованию постпоследнего элемента, а it.operator->() возвращает указатель на память за последним элементом без разыменования этого указателя.
Указатель на постпоследний элемент можно получать и использовать для сравнения с другими указателями этого массива (специальная гарантия в стандарте).
Т.е. для не пустых вектора (не bool), для array или для строки, в теории, тут я не вижу никаких проблем, а на практике там assert'ы стоят.
И каждый день — без права на ошибку...
Re[3]: получить указатель из итератора
От: rg45 СССР  
Дата: 07.12.22 22:28
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, rg45, Вы писали:


R>>То есть, использовать it.operator*() нельзя, а it.operator->() можно? Как такое может быть?

BFE>В простом случае, когда iterator::pointer — это указатель, а iterator::reference — это ссылка,

В простом случае it->x равносильно (*it).x; Вот мне и непонятно, как может быть разрешено первое, если не разрешено второе.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: получить указатель из итератора
От: B0FEE664  
Дата: 08.12.22 18:00
Оценка:
Здравствуйте, rg45, Вы писали:

R>В простом случае it->x равносильно (*it).x; Вот мне и непонятно, как может быть разрешено первое, если не разрешено второе.

А причём тут x? Речь не про x, а исключительно про адрес его.
Получение x и получение адреса x — это две разные задачи.
И каждый день — без права на ошибку...
Re[5]: получить указатель из итератора
От: rg45 СССР  
Дата: 08.12.22 19:04
Оценка:
Здравствуйте, B0FEE664, Вы писали:

R>>В простом случае it->x равносильно (*it).x; Вот мне и непонятно, как может быть разрешено первое, если не разрешено второе.

BFE>А причём тут x? Речь не про x, а исключительно про адрес его.

А что ты называешь "простым" случаем тогда? И как в этом самом случае можно обойтись без x? Как должно выглядеть валидное выражение для "простого" случая?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: получить указатель из итератора
От: K13 http://akvis.com
Дата: 09.12.22 18:15
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Так как итераторы — это обобщённые абстрактные указатели, то я предлагаю добавить каждому итератору метод get() который возвращает указатель на его объект или past-the-end указатель для past-the-end итератора или nullptr для всех случаев, когда указатель не может быть получен.

BFE>Возражения?

Ни разу не указатели.
Вот есть у меня итератор по установленным битам ( грубо -- набор значений enum отображается в целое как побитовое OR для (1<<enumValueA).
у него operator* возвращает текущий enum, а operator-> вообще не предусмотрен.
Re[5]: получить указатель из итератора
От: wander  
Дата: 10.12.22 13:56
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Получение x и получение адреса x — это две разные задачи.


Разные, но их технически нельзя различить учитывая семантику operator-> в его операторной форме.
Т.е. если бы можно было как-то перегрузить operator-> отдельно для случая, когда это просто возврат адреса, и отдельно для случая,
когда он участвует в выражении it->x, то тогда да, можно было бы ждать, что в первом случае ассерта не будет.
Re: получить указатель из итератора
От: andyp  
Дата: 10.12.22 19:55
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Есть некий итератор стандартного контейнера, а из него надо получить указатель на объект этого контейнера.


Итератор — не указатель. Какой-нибудь back_insert_iterator никогда не указывает ни на что валидное. Его разыменование позволяет втыкать нечто в конец.

BFE>Есть ли гарантия, что it.operator->() вернёт именно указатель, а не некий тип его имитирующий?


Нет. Возврат прокси часто практикуется.
Отредактировано 10.12.2022 19:57 andyp . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.