Почему void * не является типом итератора?

183
20

Я тестировал следующий код с 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, это так. И это размер наименьшей адресной единицы в компьютере.

спросил(а) 2013-10-20T23:46:00+04:00 7 лет, 5 месяцев назад
1
Решение
241

Любой тип итератора должен быть разыменованным и инкрементным, но вы не можете разыменовывать или увеличивать void*. Поскольку вы связали cppreference.com, он начинает здесь.


Относительно вашего обновленного вопроса: это по соображениям безопасности. Если вы хотите указатель на отдельные байты в памяти, вы должны использовать char*, unsigned char* или что-то в этом роде. void* - это просто способ хранения адреса, и он не должен использоваться для доступа к чему-либо. Только когда вы знаете, на что это указывает, вы должны указывать его на указатель на этот тип.

Причина, по которой вам можно добавить (или вычесть) из нее, - это AFAIK для обратной совместимости. Для void* p; вам разрешено писать p += 1;, но вам не разрешается увеличивать его с помощью ++p; по


5.3.2 Приращение и уменьшение [expr.pre.incr]

1 Операнд префикса ++ изменяется путем добавления 1 или устанавливается в true, если он bool (это использование устарело). Операнд должен быть модифицируемым значением lvalue. Тип операнда должен быть арифметическим типом или указателем на полностью определенный тип объекта.



(основное внимание).

ответил(а) 2013-10-20T23:47:00+04:00 7 лет, 5 месяцев назад
162

Почему у вас не может быть итератора для типа void?


Per §3.9.1/9 и §5.7, тип void не является полным типом, и аддитивные операторы не могут применяться к неполным типам указателей:


Тип void имеет пустой набор значений. Тип void - это неполный тип, который не может быть завершен...

... операнд (должен быть) указатель на полностью определенный объект...



Поэтому у вас не может быть итератора для пустот.


 

Почему вы видите эту ошибку?


ошибка: формирование ссылки на void



Объявляя std::iterator_traits, он где-то пытается объявить ссылку на тип записи, который void в вашем случае. но за §8.3.2/5 объявление ссылки на void не является законным, потому что вы не можете определить действительный объект void:


Ссылка должна быть инициализирована для ссылки на действительный объект


ответил(а) 2013-10-21T00:06:00+04:00 7 лет, 5 месяцев назад
122

Ответ прост, потому что вы не можете разыгрывать void*. Также void не имеет размера, поэтому вы не можете перейти к следующему элементу. Тип итератора должен быть инкрементным и разыменованным.


EDIT: -


Является ли это проблемой безопасности, то есть не позволяет людям писать плохие вещь?



Да, это по соображениям безопасности. Вы не можете делать то, что вы пытались сделать в своем редактировании. void* используется только для хранения адреса, и если вы используете его для доступа к чему-либо, это не будет разрешено.


Вы можете написать wut = wut + 1 для void * wut

ответил(а) 2013-10-20T23:48:00+04:00 7 лет, 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема