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