Подтвердить что ты не робот

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

4b9b3361

Ответ 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