C++中的空指针有什么作用?

20
我的问题很简单:在C++中,void指针有什么作用?(就是那些你用void* myptr;声明的东西)。
它们有什么用处?我能让它们指向任何类型的变量吗?
13个回答

20

基本上,这是从 C 语言遗留下来的。

它们有什么用处?

在 C 中,它们被广泛使用,但在 C++ 中,我认为它们很少需要(如果需要的话),因为我们有多态、模板等功能,这些功能提供了更清晰、更安全的方式来解决在 C 中需要使用空指针的问题。

我可以让它们指向任何类型的变量吗?

可以。然而,正如其他人所指出的那样,你不能直接使用空指针 - 你必须首先将其转换为一个具体数据类型的指针。


这让事情变得有趣了。谢谢你的快速回复 :)我知道这可能是不好的做法,但在某些情况下对我非常有用! - Dr. Acula
9
如果您正在使用C++(而不是C),那么使用void*几乎总是不正确的。为什么不通过寻找正确的处理方式来提高您的C++技能呢? - Tyler McHenry
虽然我不反对避免使用void*,因为在C++中通常有更好的方法来完成任务,但仍然存在一些不寻常的情况,它们是有价值或必需的。其中一个例子是确定一对引用是否指向同一个对象,当这些引用是多重继承对象的不同父类时。 - Steven Sudit
@Péter Török:你说得没错。MI可以要求你将类型转换为void*进行比较,这只是说明了这种语言特性可能会带来多大的麻烦。 - Steven Sudit
@Péter Török:没有任何矛盾。当我积极编写C++代码时,我几乎完全避免了MI。现在我通常使用C#进行编程,虽然它缺少MI,但允许多个接口的实现,我已经开始看到多重身份的好处。太糟糕了,C++的实现是如此痛苦。 - Steven Sudit
显示剩余2条评论

7

是的,这是一种C语言结构(不是仅限于C++),允许您声明一个指向任何类型的指针变量。您实际上不能对这样的指针做太多事情,除非将其强制转换为它实际指向的真正对象。在现代C++中,void* 已经基本过时了,在许多情况下被基于模板的通用代码所取代。


6

在C++中,void指针的少数用途之一是对new操作符进行重载。所有new操作符的返回类型均为void*。除此之外,其他人所说的都是正确的。


4

来自cplusplus.com

指针的void类型是一种特殊类型的指针。在C++中,void表示没有类型,因此void指针是指向没有类型(因此也具有未确定长度和未确定解引用属性)的值的指针。

这使得void指针可以指向任何数据类型,从整数值或浮点数到字符字符串。但是,它们有一个很大的限制:它们指向的数据不能直接进行解引用(这是合理的,因为我们没有类型可以解引用),因此我们将始终不得不将void指针中的地址转换为指向具体数据类型的其他指针类型,然后才能对其进行解引用。


4

类型隐藏。在现代C++中,它仍然具有有效的用途。挖掘一下Boost中的源代码,你会发现一些用法。通常情况下,void*的使用被深深地嵌入到更复杂的结构中,这些结构可以确保接口的类型安全,并在内部进行黑魔法。


3
他们曾经在C语言中使用void*作为指向任何东西的指针,你将这个指针传递给库函数,它们会将其作为用户数据返回给你。如果程序员不知道上下文,那么void*就毫无用处,因为你不知道它指向的是什么,所以你不能对数据进行任何操作。除非将指针传递给其他已知其含义的代码。
我不理解的是为什么人们不直接使用未定义类型,即不透明指针。这样可以保证类型安全和用户数据。
在现代C++中,void*指针几乎被多态性和模板生成的通用代码完全取代。但是,你可能仍然需要使用它们来与本地C代码进行交互。为了在任何给定的上下文中安全地使用void*,只需将一种类型转换为void*即可。这样,你就确切知道它指向的是什么。如果需要更多类型,则可以快速使用
struct safevoidptr { base* ptr };
或者
struct safevoidptr { void* ptr; int type; };
我相信dynamic_cast也可以将void*转换为多态类型,尽管我从未使用过dynamic_cast,所以不能确定。

1
一个空指针可以指向任何东西,只要它的内存足够大 :-)
C标准规定,你可以将任何指针转换为一个空指针,然后再进行强制类型转换而不会丢失任何信息。

1

void指针是最接近汇编语言指针的概念。它是一种通用指针,为地址或某个东西(函数或数据)的位置保留空间。正如其他人所说,必须在对其进行解引用之前将其强制转换。

void指针是在C语言中表示面向对象概念的流行工具。void指针的一个问题是内容可能与接收方的感知不匹配。如果调用者将指针设置为指向正方形,但接收函数期望指向猫的指针,则在进行强制转换时会发生未定义和奇怪的事情。


1

由于已经有很多好的答案,我只提供其中一个比较常见的:模板特化。如果我没有记错的话,Stroustrup的书中有一个例子:将vector作为vector进行特化,然后让vector从vector派生(私有)。这样,vector将只包含直接易于内联的代码(即从vector调用相关函数)。这将减少在使用许多不同类型指针的程序中编译vector时的重复数量。


0

在 C 中可以使用 void,但在 C++ 中不能做的事情:

void* 会自动转换为其他指针类型。 (你知道它是一个 void* - 强制显式转换不会增加类型安全性)

Struct* p = malloc( sizeof(Struct) );
// vs C++
Struct* p = (Struct*)malloc( sizeof(Struct) );
// Some will argue that that cast style is deprecated too, and c++ programmers 
// need to actually do this:
Struct* p = reinterpret_cast<Struct*>malloc( sizeof(Struct) );
// See what C++ did there? By making you write Struct a 3rd time, you can now be sure
// you know what you are doing!

在C语言中,void*也可以进行间接计数,这使得在将指针传递给需要指向指针的函数时更加安全。

void funcInitializingOutPtr( void** ppOut)
{
  *ppOut = malloc( x );
}

int* out = NULL;
funcInitializingPtr(out);  // C would signal this as an error
funcInitializingPtr(&out); // correct
// vs C++ 
funcInitializingPtr( (void**)&out ); // so much safer needing that exlicit cast.
funcInitializingPtr( (void**)out);   // oops. thanks C++ for hiding the common error

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接