为什么无法引用无效?

Luc*_*lle 39 c++ reference void-pointers

为什么无法引用void?我在C++标准中找到的唯一内容就是这一行,见8.3.2.1

指定类型"对cv void的引用"的声明符是不正确的.

为什么会那样?为什么我不能写一个接受一个"通用"的函数void&

为了清楚起见,我没有任何有用的应用程序,使用引用void可能比使用模板更好,但我只是好奇禁止这个结构的基本原理.


为了澄清一点,我理解使用"按原样"引用"无效"将与取消引用指向void的指针一样毫无意义.不过,我可以把它转换为参考TO- sometype.这时候为了使用它,我能不能?事实上,我不明白为什么下面的代码片段可以工作......

void foo(void *data)
{
    int *i = reinterpret_cast<int*>(data);
    // do something with i
}
Run Code Online (Sandbox Code Playgroud)

......虽然这个不能:

void foo(void &data)
{
    int &i = reinterpret_cast<int&>(data);
    // do something with i
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*ley 39

如果你确实提到了void,你会用它做什么?它不是数字,字符,指针或类似的东西.您的假设通用函数无法对其执行任何操作,除了获取其地址(而不是其大小).

"void"有两个用途:放弃任何类型的知识(如void*),并指定任何东西而不是某些东西(void函数返回).在这两种情况下都不可能对某个空白说些什么,除了它可能有一个地址.

如果你想不出某种方式可以有用,而我却做不到,那至少证明某些东西是无用的,而这可能至少是这里理论的一部分.

  • 我觉得这是一个用例无效引用:不像一个空指针(可以是`nullptr`),空隙参考会给你一个保证,就是引用实际上指的是什么,即使你不能提供有关静态保证它的类型是什么. (17认同)
  • 如果 `void&amp;` 没有用,就没有理由禁止它。该标准固执己见,并引入了不必要的例外。 (5认同)
  • 那么实际上你可以使用void引用做一些事情,顺便说一句就是语法:你可以传递对象而不用&取消引用它,它是愚蠢但我不喜欢使用很多&周围,我使用refs发现更清楚 (3认同)
  • 对 void 的引用具有在构造函数中用作通用引用参数的有用属性。因此,您可以拥有 Foo a(anyReference) 并且它可以在内部将其转换为空指针。反过来,它允许您传递引用,并且构造函数可以为您将其转换为指针。当然,它与惯用的 C++ 相去甚远,但 C++ 是一种多范式语言,在一个地方被认为危险的事物在另一个地方被视为一种驱动力。并且如前所述,在构造函数中使用 void 引用比在构造函数中使用 void 指针更安全。 (3认同)
  • 我看不出这如何回答问题。OP的假设功能如何不起作用?本质上,它将提供与“ void *”相同的功能,但更加确定的是它不是null (2认同)

Bin*_*ier 14

首先问问你自己,你将如何取消引用无效指针?

void *p = /*something*/ ;
cout << *p << endl;
Run Code Online (Sandbox Code Playgroud)

上面的代码没有意义,我们无效的原因之一是我们可以说"我需要在这里做一些通用指针工作,我既不知道也不关心我指向的是什么".根据定义,编译器不知道void*指向什么,因此它不能取消引用它.你可以 - 通过强制转换 - 但编译器不能.

对void的引用会受到同一问题的影响,根据定义,指向的数据没有类型,因此无法以任何有意义的方式引用它.

要引用它 - 程序员 - 需要将其转换为其他类型,然后您可以对其进行类型化引用.

不确定我是否也像我想的那样解释了这一点.

鲁本,有什么想法吗?

编辑:回答你的编辑.

采取第一个函数,您传递void*data.数据是一个完全有效的项目,您可以使用它进行计算,或者如果您实施了一些日志记录,则可以记录它.

logger << data;
Run Code Online (Sandbox Code Playgroud)

并且您将获得地址数据指向.如果您尝试取消引用数据,编译器将给您一个错误(暂时没有C++编译器,所以不确定实际错误).例如

void* data = /* some assignment */;
logger << *data; // compiler error.
Run Code Online (Sandbox Code Playgroud)

现在,编译器不会因为任何原因而让你取消引用void*(它没有意义),同样代表对void和data的引用,除了因为它是一个引用它一直被隐式取消引用.编译器不允许您在一次操作中取消引用void*,它不会让您不断地取消引用它.

void& data = /* some assignment *.;
logger << data; // means same as logger << *data above
Run Code Online (Sandbox Code Playgroud)

你不能对数据做任何事情除了拿它的地址,并且有一个完美的 - 安全 - 方法内置到语言中去做,即

void* data;
Run Code Online (Sandbox Code Playgroud)

这有什么意义吗?

  • 我完全同意使用引用"按原样"就像取消引用指向void的指针:无意义.但是,我可以使用引用reinterpret_cast以便我可以使用它,我错了吗?我会编辑我的问题以反映这些想法. (2认同)

Chr*_*isW 6

引用是对某事物实例的引用.某事物的实例不可能是一种类型void.某些事物的实例必须具有特定类型(可能还有基类型).


小智 6

好吧,有一件事困扰着我。void*如上所述,a 的想法是您仍然有一个包含地址的有效变量,但类型被忽略。这似乎是允许的,因为我们仍然可以使用地址数据 - 在这种情况下,类型有点多余(或不太重要)。取消引用它是不好的,因为尝试访问成员没有意义,例如p.mem。我们不知道要引用哪个类,因此不知道要跳转到的内存,也不知道要遵循的 vtable 指针。

然而,似乎它p本身就可以了,因为它只引用对象,而不引用它的任何数据。不需要班级信息即可完成此操作,只需地址即可。我知道这绝对没有用,但它对于定义事情何时发生故障很重要。允许这个概念,C++ 引用(不断取消引用但不访问任何内容)例如void& ref = static_cast< &void >(obj)也是有意义的,因此将允许空引用。我并不是说任何人都应该向负责人提出这个问题,但从“有意义”的角度来看,这似乎是正确的,不是吗?

正如 Luc Touraille 上面指出的那样(至少这是我的解释),它可以实现,但问题是语义问题。我能想到的合理解释是,由于对象变量是内存序列的“标签”,因此类型具有重要的语义价值。因此,指针被视为具有地址值的变量,将类型视为有点多余 - 不是定义它的关键。

有人同意吗?