Регистрация адресов памяти
Если вы хотите вывести указатель с помощью iostreams (например, для ведения журнала), то использование 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 overload operator void*
в качестве проверки состояния, поэтому такой синтаксис, как if (stream)
или while (stream)
, является кратким способом проверки состояния потока.
Шаблон метапрограммирования
Возможно, вы захотите использовать void*
с шаблонным метапрограммированием, иногда как уменьшенный улов, например, с трюками SFINAE, но чаще всего есть лучший способ обойти это, используя частичную специализацию той или иной формы.
Доступ к наиболее производному указателю
Как отметил Альф в комментариях dynamic_cast<void*>
также полезно для получения наиболее производного типа в иерархии, например ::1010 *
#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 использует
Существует множество "устаревших" C, использующих void*
для хранения указателей на данные, не зная, что это такое, но в новом коде C ++ почти всегда есть лучший способ выразить ту же функциональность.