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



Я протестировал следующий код с GCC 4.8, который не компилируется, потому что мы не можем сформировать ссылку на void.



#include <iterator>
int main()
{
std::iterator_traits<void*> test;
}


Означает ли это, что void* не является итератором ? (имеется в виду понятие здесь)



Редактировать:



Хорошо, вопрос был плохо сформулирован. На самом деле я спрашиваю, зачем C++ нужно такое поведение для 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;
}


Таким образом, даже если, как вы сказали, пустота не имеет размера, с точки зрения GCC, она имеет. И это размер самого маленького адресуемого блока в компьютере.
744   3  

3 ответов:

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


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

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

5.3.2 инкремента и декремента [выраж.пре.incr]

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

(Курсив мой).

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

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

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

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

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

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

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

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

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

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

Править:-

Это из соображений безопасности, то есть, чтобы люди не писали плохо вещь ?

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

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

Comments

    Ничего не найдено.