void *是否合法使用?

时间:2015-12-14 17:07:50

标签: c++

在C ++中是否合法使用void*?或者这是因为C有它吗?

回顾一下我的想法:

输入:如果我们想要允许多种输入类型,我们可以重载函数和方法,或者我们可以定义一个公共基类或模板(感谢在答案中提到这一点)。在这两种情况下,代码都更具描述性,更不容易出错(假设基类以理智的方式实现)。

输出:我想不出任何我希望接收void*而不是从已知基类派生的东西的情况。

只是为了明确我的意思:我并没有特别询问void*是否有用例,但是如果有void*是最佳或仅可用的情况选择。以下几个人已经完全回答了这个问题。

9 个答案:

答案 0 :(得分:80)

void*至少是::operator new(也是每operator new ...)和malloc以及展示位置{{1}的结果所必需的运营商。

new可以被认为是每种指针类型的常见超类型。所以它并不是指向void*的指针,而是指向任何东西的指针。

顺便说一句,如果您想保留几个不相关的全局变量的某些数据,那么在声明全局voidstd::map<void*,int> score;以及int x;之后,您可以使用一些double y; std::string s;score[&x]=1;以及score[&y]=2;

memset需要score[&z]=3;地址(最通用的地址)

此外,POSIX系统有dlsym,其返回类型显然应为void*

答案 1 :(得分:28)

使用void*有多种原因,最常见的是:

  1. 在其界面中使用void*与C库进行交互
  2. 类型擦除
  3. 表示未打字的内存
  4. 以相反的顺序,用void*(3)而不是char*(或变体)表示未打字的内存有助于防止意外指针算术; void*上的操作很少,因此通常需要在有用之前进行转换。当然,与char*非常相似,别名也没有问题。

    Type-erasure(2)仍然在C ++中使用,或者与模板一起使用:

    • 非通用代码有助于减少二进制膨胀,即使在通用代码中也可用于冷路径
    • 有时需要非通用代码进行存储,即使在std::function
    • 等通用容器中也是如此

    显然,当您处理的界面使用void*(1)时,您别无选择。

答案 2 :(得分:15)

哦,是的。即使在C ++中,有时我们使用void *而不是template<class T*>,因为有时模板扩展中的额外代码会过重。

通常我会将它用作类型的实际实现,模板类型将继承它并包装强制转换。

此外,自定义slab分配器(运营商新实现)必须使用void *。这就是为什么g ++在void *上添加了允许指针算术的扩展名的原因之一,就像它的大小为1一样。

答案 3 :(得分:10)

  

输入:如果我们想要允许多种输入类型,我们可以重载   功能和方法

真。

  

或者我们可以定义一个共同的基础   类。

这部分正确:如果无法定义公共基类,接口或类似内容,该怎么办?要定义您需要访问源代码的那些,这通常是不可能的。

你没有提到模板。但是,模板无法帮助您实现多态:它们使用静态类型,即在编译时已知。

void*可被视为最低共同标准。在C ++中,你通常需要它,因为(i)你本身不能做很多事情,而且(ii)几乎总有更好的解决方案。

更进一步,您通常会将其转换为其他具体类型。这就是char *通常更好的原因,虽然它可能表明你期待的是C风格的字符串,而不是纯粹的数据块。这就是void*优于char*的原因,因为它允许从其他指针类型进行隐式转换。

你应该接收一些数据,使用它并产生输出;要实现这一点,您需要知道您正在使用的数据,否则您遇到的问题与您最初解决的问题不同。例如,许多语言没有void*并且没有问题。

另一种合法用途

当使用printf等函数打印指针地址时,指针应具有void*类型,因此,您可能需要转换为void *

答案 4 :(得分:7)

是的,它与语言中的任何其他内容一样有用 例如,您可以使用它来擦除您在需要时可以静态强制转换为正确类型的类的类型,以便拥有最小且灵活的界面。

that回复中,有一个使用示例可以给你一个想法 为了清楚起见,我将其复制并粘贴在下面:

class Dispatcher {
    Dispatcher() { }

    template<class C, void(C::*M)() = C::receive>
    static void invoke(void *instance) {
        (static_cast<C*>(instance)->*M)();
    }

public:
    template<class C, void(C::*M)() = &C::receive>
    static Dispatcher create(C *instance) {
        Dispatcher d;
        d.fn = &invoke<C, M>;
        d.instance = instance;
        return d;
    }

    void operator()() {
        (fn)(instance);
    }

private:
    using Fn = void(*)(void *);
    Fn fn;
    void *instance;
};

显然,这只是void*的一大堆用途之一。

答案 5 :(得分:4)

与返回指针的外部库函数接口。这是一个Ada应用程序。

extern "C" { void* ada_function();}

void* m_status_ptr = ada_function();

这会返回一个指向Ada想要告诉你的内容的指针。你不必对它做任何事情,你可以把它还给Ada来做下一件事。 事实上,在C ++中解开Ada指针并非易事。

答案 6 :(得分:2)

简而言之,C ++作为一种严格的语言(不考虑像 malloc()这样的C文物)需要void *,因为它没有所有可能类型的共同父类。与ObjC不同,例如,它具有对象

答案 7 :(得分:1)

我想到的第一件事(我怀疑是上面几个答案的具体案例)是将对象实例传递给Windows中的threadproc的能力。

我有几个需要这样做的C ++类,它们有工作线程实现,CreateThread()API中的LPVOID参数获取类中静态方法实现的地址,因此工作线程可以使用类的特定实例来完成工作。 threadproc中的简单静态强制转换产生要使用的实例,允许每个实例化对象具有来自单个静态方法实现的工作线程。

答案 8 :(得分:0)

如果是多重继承,如果需要获取指向对象占用的内存块的第一个字节的指针,则可以dynamic_castvoid*