C++ 什么时候使用空指针?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1025579/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When to use a void pointer?
提问by Mac13
I understand the use of void pointer for malloc implementation.
我了解使用 void 指针进行 malloc 实现。
void* malloc ( size_t size );
Can anyone suggest other reasons or provide some scenarios where it is useful in practice.
任何人都可以提出其他原因或提供一些在实践中有用的场景。
Thanks
谢谢
回答by Artem Barger
One good scenario void*
use is when you want to implement any generic ADT's, in case you just don't know what datatype it going to keep and deal with. For example, a linked list like the following:
一个很好的场景void*
用途是当您想要实现任何通用 ADT 时,以防您不知道它将保留和处理什么数据类型。例如,如下所示的链表:
typedef struct node_t node;
struct
{
void* data;
node* prev, next;
} node_t;
typedef struct list_t list;
typedef void* (func)(void*) cpy_func;
typedef void (func)(void*) del_func;
struct
{
node* head, tail, curr;
cpy_func copy;
del_func delete;
} list_t;
initializeLinkedList(cpy_func cpy, del_func del);
//here you keep going defining an API
Here for example you will pass in initialization function pointers to other functions which will be capable of copying your datatype to your list and freeing it afterwards. So by using void*
you make your list more generic.
例如,您将在此处将初始化函数指针传递给其他函数,这些函数将能够将您的数据类型复制到您的列表中并在之后释放它。因此,通过使用void*
您可以使您的列表更通用。
I think void*
remained in C++ only because of backward compatibility, since in C++ you have more safe and sophisticated ways to achieve the same result like templates, functors, etc., and you don't need to use malloc while programming C++.
我认为void*
留在 C++ 中只是因为向后兼容性,因为在 C++ 中,您有更安全和复杂的方法来实现相同的结果,如模板、函子等,并且在编程 C++ 时不需要使用 malloc。
Regarding C++, I don't have any specific useful examples.
关于 C++,我没有任何具体有用的例子。
回答by Kekoa
If you are interfacing with C code and need to pass through a C++ object, but a C library will only take a generic pointer, then when you retrieve the pointer you need to re-cast it to the proper type.
如果您正在与 C 代码交互并需要通过 C++ 对象,但 C 库将只接受一个通用指针,那么当您检索该指针时,您需要将其重新转换为正确的类型。
Void pointers probably shouldn't be used very often, but they can help when you're trying to use a library function that works with arbitrary pointers, and doesn't really care what data is represented by that memory.
空指针可能不应该经常使用,但是当您尝试使用可以处理任意指针的库函数并且并不真正关心该内存表示什么数据时,它们会有所帮助。
回答by Gerhard
void
pointers should be used any time the contents of a block of data is not important. For example when copying data the contents of a memory area is copied but the format of the data is not important.
void
任何时候都应该使用指针,数据块的内容并不重要。例如,在复制数据时,会复制内存区域的内容,但数据的格式并不重要。
For functions that operate on blocks of memory without needing to understand the contents using void
pointers clarifies the design to users so that they know the function does not care for any data format.
Often functions a coded to take a char *
to handle blocks of memory when the function is actually content agnostic.
对于在内存块上操作而无需理解内容的函数,使用void
指针向用户阐明了设计,以便他们知道该函数不关心任何数据格式。char *
当函数实际上是内容不可知的时,通常函数 a 编码来处理内存块。
回答by Josh
In C++, I've found the most compelling use case for void* pointers is to give code the option to store arbitrary "user data" on an object they are already using.
在 C++ 中,我发现 void* 指针最引人注目的用例是让代码可以选择在他们已经使用的对象上存储任意“用户数据”。
Let's say you've written a class representing a Car
, for use in software which does useful things with Car
objects (traffic simulation, rental car inventory, whatever). Now let's say you find yourself in a situation where your application wants to keep track of the arbitrary contents of the trunk of a Car
. The details of what's stored in the trunk are not important to the Car
class, and could be anything -- it really depends on the purpose of the application using the Car class. Enter the void* pointer.
假设您编写了一个表示 a 的类Car
,用于对Car
对象执行有用操作的软件(交通模拟、租车库存等)。现在假设您发现自己的应用程序想要跟踪Car
. 存储在主干中的详细信息对Car
类来说并不重要,可以是任何东西——这实际上取决于使用 Car 类的应用程序的目的。输入 void* 指针。
class Car
{
public:
// Existing methods of your Car class
void setContentsOfTrunk(void* contentsOfTrunk);
void* contentsOfTrunk() const;
private:
void* m_contentsOfTrunk;
}
Now, any application using your Car
class has the option to attach an arbitrary data object to an existing Car
object such that it can be obtained from any code which has the Car
object. The contents of the trunk "travel with" the Car
object, wherever it goes in your code.
现在,任何使用您的Car
类的应用程序都可以选择将任意数据对象附加到现有Car
对象,以便可以从具有该Car
对象的任何代码中获取该对象。主干的内容“随”Car
对象,无论它在代码中的任何位置。
There are two alternatives to using void* in this case.
在这种情况下,有两种使用 void* 的替代方法。
The first is to template your class based on the type of the trunk contents object:
第一个是根据主干内容对象的类型来模板化你的类:
template <class TrunkContentsType>
class Car
{
public:
// Existing methods of your Car class
void setContentsOfTrunk(TrunkContentsType contentsOfTrunk);
TrunkContentsType contentsOfTrunk() const;
private:
TrunkContentsType m_contentsOfTrunk;
}
This seems unnecessarily invasive. The type of the contents of the trunk are important only to the application. Algorithms and data structures working with Car objects don't care what's in the trunk. By templating the class, you're forcing applications using the class to choose a type for trunk contents, but in many cases the applications don't care about trunk contents either.
这似乎是不必要的侵入性。主干内容的类型仅对应用程序很重要。使用 Car 对象的算法和数据结构并不关心后备箱中有什么。通过对类进行模板化,您将强制使用该类的应用程序选择中继内容的类型,但在许多情况下,应用程序也不关心中继内容。
The second alternative is to derive a new class from Car which adds a data member and accessors for trunk contents:
第二种选择是从 Car 派生一个新类,它为后备箱内容添加数据成员和访问器:
class Car
{
public:
// Existing methods of your Car class
// No methods having anything to do with trunk contents.
private:
// No data member representing trunk contents.
}
class CarWithTrunkContents
{
public:
// Existing methods of your Car class
void setContentsOfTrunk(TrunkContentsType contentsOfTrunk);
TrunkContentsType contentsOfTrunk() const;
private:
TrunkContentsType m_contentsOfTrunk;
}
The new CarWithTrunkContents
class is an application-specific class which adds a data member of the type the application needs to store trunk contents on the car. This also seems unnecessarily heavyweight. Why do you have to derive a whole new class to add an additional piece of data which doesn't affect the behavior of the class? And if it's fairly common for applications using the Car
class to want to store trunk contents, why force each application to derive a new class for their particular type of trunk contents?
新CarWithTrunkContents
类是特定于应用程序的类,它添加了应用程序需要在汽车上存储行李箱内容的类型的数据成员。这似乎也是不必要的重量级。为什么必须派生一个全新的类来添加不影响类行为的额外数据?如果使用Car
该类的应用程序想要存储主干内容是相当普遍的,那么为什么要强制每个应用程序为其特定类型的主干内容派生一个新类呢?
Finally, while my contrived example of trunk contents maybe paints a vivid picture of arbitrary trunk contents traveling with the Car
object, in practice you would likely provide an even more general mechanism for attaching application-specific data to the Car
:
最后,虽然我人为的主干内容示例可能描绘了随Car
对象移动的任意主干内容的生动画面,但在实践中,您可能会提供一种更通用的机制来将特定于应用程序的数据附加到Car
:
class Car
{
public:
// Existing methods of your Car class
void setUserData(void* userData);
void* userData() const;
private:
void* m_userData;
}
This way, an application can attach an object representing trunk contents, or an object representing driver's license and registration, or an object representing rental agreement, or whatever. I've seen this kind of void* pointer referred to as "userData" (i.e. understood by the user of the class), "blindData" (i.e. the class is blind to the contents of the object it carries) or "applicationData" (i.e. data of type and purpose defined by the application).
通过这种方式,应用程序可以附加一个表示后备箱内容的对象,或者一个表示驾驶执照和注册的对象,或者一个表示租赁协议的对象,等等。我见过这种称为“userData”(即被类的用户理解)、“blindData”(即该类对其携带的对象的内容视而不见)或“applicationData”(即应用程序定义的类型和用途的数据)。
回答by micmoo
A GREAT way to learn all about void * and other C topics is to watch the first half of the fantastic Stanford "Programming Paradigms" on iTunes-U. It really explains void * (C generics) and pointers in general fantastically! It definately helped me learn C better...
了解有关 void * 和其他 C 主题的一个很好的方法是在 iTunes-U 上观看精彩的斯坦福“编程范式”的前半部分。它真的很好地解释了 void * (C 泛型) 和一般的指针!它绝对帮助我更好地学习 C...
One of the biggest uses is to use void * if you want to be able to accept different types of data in a function. (heres an example: http://142.132.30.225/programming/node87.html)
如果您希望能够在函数中接受不同类型的数据,那么最大的用途之一就是使用 void *。(这里有一个例子:http: //142.132.30.225/programming/node87.html)
Here's a further example of what you can use them for:
这是您可以将它们用于什么的进一步示例:
int i;
char c;
void *the_data;
i = 6;
c = 'a';
the_data = &i;
printf("the_data points to the integer value %d\n", *(int*) the_data);
the_data = &c;
printf("the_data now points to the character %c\n", *(char*) the_data);
If you don't want to watch the free stanford classes, i'd recommend googling void pointer and reading all the material there.
如果您不想观看免费的斯坦福课程,我建议您使用谷歌搜索 void 指针并阅读那里的所有材料。
回答by quant_dev
It is commonly used in numerical code, for example a C root solver function might look like that:
它通常用于数字代码,例如 C 根求解器函数可能如下所示:
double find_root(double x0, double (*f)(double, void*), void* params)
{
/* stuff */
y = f(x, params);
/* other stuff */
}
params
is cast by f
to some structure it knows about, but find_root
doesn't.
params
被转换f
为它知道但find_root
不知道的某种结构。
回答by Tomek Szpakowicz
Another example of such C "generics", implemented with void *, is a standard qsort function:
使用 void * 实现的此类 C“泛型”的另一个示例是标准的 qsort 函数:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
You can sort an array of any type: int, long, double, char * or some struct pointers...
您可以对任何类型的数组进行排序:int、long、double、char * 或一些结构指针...
回答by Pieter
Next to interfacing with C, I find myself only using void pointers when I need to debug / trace some code and like to know the address of a certain pointer.
在与 C 接口之后,我发现自己只在需要调试/跟踪某些代码并想知道某个指针的地址时才使用 void 指针。
SomeClass * myInstance;
// ...
std::clog << std::hex << static_cast< void* >(myInstance) << std::endl;
Will print something like
会打印类似的东西
0x42A8C410
And, in my opinion, nicely documents what I'm trying to do (know the pointer address, not anything about the instance)
而且,在我看来,很好地记录了我正在尝试做的事情(知道指针地址,而不是关于实例的任何信息)
回答by i_am_jorf
Void pointers are useful when you write code that needs to run on multiple operating systems and needs to be fairly agnostic of underlying framework APIs.
当您编写需要在多个操作系统上运行并且需要对底层框架 API 完全不可知的代码时,空指针非常有用。
For example, OS X, Windows and Linux all have the basic concept of a window object, but they're all very different. So I have common code that passes them around as void*'s and then platform specific implementations that cast the void* to the native type (HWND, etc).
例如,OS X、Windows 和 Linux 都有窗口对象的基本概念,但它们都非常不同。所以我有通用代码将它们作为 void* 传递,然后是平台特定的实现,将 void* 转换为本机类型(HWND 等)。
But, yeah, as others have said in this thread, this sort of thing is certainly to be avoided except where necessary.
但是,是的,正如其他人在此线程中所说的那样,除非必要,否则肯定要避免这种事情。
回答by Mordachai
void *
is really a C-ism, and allows C to do some things that it could not reasonably do otherwise.
void *
是真正的 C 主义,并允许 C 做一些它在其他情况下无法合理做的事情。
char *
cannot portably be used for anything, as different platforms can make different types of pointers - a char *
isn't necessarily handled the same (or is even the same size) as a void *
.
char *
不能可移植地用于任何事情,因为不同的平台可以制作不同类型的指针 - achar *
不一定与void *
.
So when the type of data isn't known in C (or is polymorphic or otherwise dynamic), then void *
allows you to generate the correct underlying pointer type - one that can point to anything correctly.
因此,当数据类型在 C 中未知(或者是多态的或动态的)时,则void *
允许您生成正确的底层指针类型 - 可以正确指向任何内容的指针类型。
In C++ void *
generally should never come up except in the context of interfacing with legacy C code in one form or another.
在 C++ 中void *
,除非在以一种或另一种形式与遗留 C 代码接口的上下文中,否则通常不应该出现。