我已经使用GCC 4.8测试了以下代码,但由于我们无法形成对void的引用,因此无法编译。
#include <iterator>
int main()
{
std::iterator_traits<void*> test;
}
这是否意味着void *不是iterator? (意思是这里的概念)
修改
好的问题是形成不良。我实际上问的是为什么C ++需要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;
}
因此,正如你所说,从GCC的角度来看,空虚的规模并不大,确实如此。它是计算机中最小的可加压单元的大小。
答案 0 :(得分:30)
任何迭代器类型都需要可解除引用且可递增,但您不能取消引用或增加void*
。自从您关联cppreference.com
后,它就会启动here。
关于您更新的问题:出于安全原因。如果你想要一个指向内存中各个字节的指针,你可以使用char*
,unsigned char*
或类似的东西。 void*
基本上只是一种存储地址的方式,它不应该被用来访问任何东西。只有当你知道它指向的是什么时,你才应该将它转换为指向该类型的指针。
允许您添加(或减去)的原因是AFAIK是为了向后兼容。对于void* p;
,您可以编写p += 1;
,但 允许您使用++p;
按
5.3.2递增和递减[expr.pre.incr]
1 前缀
++
的操作数通过添加1
进行修改,如果是true
则设置为bool
(此用途为不建议使用)。操作数应是可修改的左值。操作数的类型应为算术类型或指向完全定义的对象类型的指针。
(强调我的)。
答案 1 :(得分:13)
每§3.9.1/9
和§5.7
,类型void
不是完整类型,添加运算符不能应用于不完整的指针类型:
void类型有一组空值。 void类型是不完整类型,不能是&gt;完成...
...操作数是 (必须) 指向完全定义的对象的指针......
因此,您无法获得空洞的迭代器。
错误:形成对void的引用
声明std::iterator_traits
,它在某处尝试声明对您的案例中void
的条目类型的引用。但是根据§8.3.2/5
声明对void
的引用是不合法的,因为您无法定义void
的有效对象:
应初始化引用以引用有效对象
答案 2 :(得分:7)
答案很简单,因为你无法取消引用void*
。 void也没有大小,所以你不能移动到下一个项目。迭代器类型必须是增量和可解除引用的。
修改: - 强>
是出于安全考虑,即阻止人们写错 事情?
是的,这是出于安全原因。您无法在编辑中执行您尝试执行此操作的操作。 void*
仅用于存储地址,如果您使用它来访问任何内容,则不允许这样做。
您可以为wut = wut + 1
void * wut