除了与内存分配相关的东西之外,还是必须的

时间:2011-09-04 11:27:34

标签: c++ void-pointers

除了C ++中与内存分配相关的内容之外,还需要void*吗? 你能举个例子吗?

6 个答案:

答案 0 :(得分:5)

记录内存地址

如果你想使用iostream输出一个指针(例如用于记录),那么通过void*进行是确保operator<<没有以某种疯狂方式过载的唯一方法。

#include <iostream>

struct foo {
};

std::ostream& operator<<(std::ostream& out, foo*) {
  return out<<"it's a trap!";
}

int main() {
  foo bar;
  foo *ptr = &bar;

  std::cout << ptr << std::endl;
  std::cout << static_cast<void*>(ptr) << std::endl;
}

测试iostream状态

iostreams重载operator void*作为状态检查,因此像if (stream)while (stream)这样的语法是测试流状态的简便方法。


模板元编程

您可能希望将void*模板元编程有时用作减少捕获全部,例如使用SFINAE技巧,但通常使用某种形式的部分特化可以更好地解决它。


访问大多数派生指针

正如Alf在评论dynamic_cast<void*>中指出的那样,对于获取层次结构中最派生的类型也是有用的,例如:

#include <iostream>

struct other {
  virtual void func() = 0;
  int c;
};

struct foo {
  virtual void func() { std::cout << "foo" << std::endl; }
  int a;
};

struct bar : foo, other {
  virtual void func() { std::cout << "bar" << std::endl; }
  int b;
};

namespace {
  void f(foo *ptr) {
    ptr->func();
    std::cout << ptr << std::endl;
    std::cout << dynamic_cast<void*>(ptr) << std::endl;
  }

  void g(other *ptr) {
    ptr->func();
    std::cout << ptr << std::endl;
    std::cout << dynamic_cast<void*>(ptr) << std::endl;
  }
}

int main() {
  foo a;
  bar b;
  f(&a);
  f(&b);
  g(&b);
}

给出:

foo
0xbfb815f8
0xbfb815f8
bar
0xbfb815e4
0xbfb815e4
bar
0xbfb815ec
0xbfb815e4

在我的系统上。


例外

§15.3.1陈述:

  

异常声明不应表示指针或引用   不完整的类型,除了void *,const void*,volatile void *或者   const volatile void *。

因此,似乎是通过void*捕获指向不完整类型的指针的唯一合法方式。 (虽然我认为如果你真的需要使用它可能会有更大的问题)


Legacy C使用

void*有很多“遗留”C用于存储指向数据的指针而不知道它是什么,但在新的C ++代码中,几乎总有一种表达相同功能的更好方法。

答案 1 :(得分:2)

外部库经常使用它们(特别是在C中)。

在这种情况下,我通常会隐藏这些库的使用(或更危险的部分)。我通过在它们周围编写接口来隐藏它们(比如包装)。我写的接口用于将类型安全引入程序。在这种情况下,void*可能是必需的,但至少它是隐藏的并且仅限于方法或回调。

答案 2 :(得分:2)

void*经常用于回调。

  

回调通常使用函数在C语言中实现   作为void指针传递的指针和辅助用户定义数据   泛型。

[from here]

当然,这不是类型安全的,所以人们想出办法包装这类东西,like here

答案 3 :(得分:1)

不,不是。引用非类型内存

只是一个成语

答案 4 :(得分:1)

您可能想要使用void的一种情况是在传递数据缓冲区时,例如在此函数中:

void loadData(void* data, std::size_t size)

许多代码通过char-pointer而不是void-pointer传递缓冲区,因为通常情况下,缓冲区以1字节块的形式读取,这恰好是C ++标准确保char为有

但是,使用void-pointers更通用。这是函数告诉你的一种方式,“只要给我一些数据,不要担心我会如何阅读它”。然后,该函数可以转换指针并以块或其喜欢的大小读取数据。

答案 5 :(得分:1)

void *在C ++中用于表示未知结构的指针类型。

所以每当我有一个指针类型时我会使用它,代码不应该知道那里有什么:

  • 内存分配
  • 容器
  • ...

通常无效*与模板代码混合得很好,以避免模板引起的代码膨胀。

想象一下你实现了

template <typename T>
class vector {
 /*stuff */
};

然后,您可以为T *创建一个模板特化,它使用void指针,因此代码不会重复。