Почему void * не является типом итератора?
Я тестировал следующий код с GCC 4.8, который не компилируется, потому что мы не можем создать ссылку на void.
#include <iterator>
int main()
{
std::iterator_traits<void*> test;
}
Означает ли это, что void * не является iterator? (что означает понятие здесь)
EDIT:
Хорошо, что вопрос был плохо сформирован. Я действительно спрашиваю, почему С++ нуждается в таком поведении для void *? Это касается проблем безопасности, то есть не позволяет людям писать плохие вещи?
Поскольку в то время как отсрочка void является незаконной, арифметика указателя такова:
int main()
{
std::uint8_t test[] = {1,2,3};
void * wut = test;
std::uint8_t * p2 = static_cast<std::uint8_t *>(wut + 1);
std::cout << std::hex << static_cast<int>(*p2) << std::endl;
}
Итак, даже если, как вы сказали, void не имеет размера, с точки зрения GCC, это так. И это размер наименьшей адресной единицы в компьютере.
Ответы
Ответ 1
Любой тип итератора должен быть разыменованным и инкрементным, но вы не можете разыменовывать или увеличивать void*
. Поскольку вы связали cppreference.com
, он начинает здесь.
Относительно вашего обновленного вопроса: это по соображениям безопасности. Если вы хотите указатель на отдельные байты в памяти, вы должны использовать char*
, unsigned char*
или что-то в этом роде. void*
- это просто способ хранения адреса, и он не должен использоваться для доступа к чему-либо. Только когда вы знаете, на что это указывает, вы должны указывать его на указатель на этот тип.
Причина, по которой вам можно добавить (или вычесть) из нее, - это AFAIK для обратной совместимости. Для void* p;
вам разрешено писать p += 1;
, но вам не разрешается увеличивать его с помощью ++p;
по
5.3.2 Приращение и уменьшение [expr.pre.incr]
1 Операнд префикса ++
изменяется путем добавления 1
или устанавливается в true
, если он bool
(это использование устарело). Операнд должен быть модифицируемым значением lvalue. Тип операнда должен быть арифметическим типом или указателем на полностью определенный тип объекта.
(основное внимание).
Ответ 2
Почему у вас не может быть итератора для типа void?
Per §3.9.1/9
и §5.7
, тип void
не является полным типом, и аддитивные операторы не могут применяться к неполным типам указателей:
Тип void имеет пустой набор значений. Тип void - это неполный тип, который не может быть завершен...
... операнд (должен быть) указатель на полностью определенный объект...
Поэтому у вас не может быть итератора для пустот.
Почему вы видите эту ошибку?
ошибка: формирование ссылки на void
Объявляя std::iterator_traits
, он где-то пытается объявить ссылку на тип записи, который void
в вашем случае. но за §8.3.2/5
объявление ссылки на void
не является законным, потому что вы не можете определить действительный объект void
:
Ссылка должна быть инициализирована для ссылки на действительный объект
Ответ 3
Ответ прост, потому что вы не можете разыгрывать void*
. Также void не имеет размера, поэтому вы не можете перейти к следующему элементу. Тип итератора должен быть инкрементным и разыменованным.
EDIT: -
Является ли это проблемой безопасности, то есть не позволяет людям писать плохие вещь?
Да, это по соображениям безопасности. Вы не можете делать то, что вы пытались сделать в своем редактировании. void*
используется только для хранения адреса, и если вы используете его для доступа к чему-либо, это не будет разрешено.
Вы можете написать wut = wut + 1
для void * wut