施放到空*并返回Original_Data_Type*
Casting to void* and Back to Original_Data_Type*
我已经看到并使用了很多次,这是C++,特别是在各种线程实现中。我想知道这样做是否有任何陷阱/问题?当我们投射到 void* 并再次返回时,有什么方法可以遇到错误或未定义的条件吗?如果有这些问题,我们应该如何解决?
谢谢。
完全有效的。以下是标准对它的看法:
§4.10 指针转换
2 "指向 cv
T
的指针"类型的右值,其中T
是一个对象 类型,可以转换为类型为"指向 cv 的指针"的右值void
。"将"指向 cvT
的指针"转换为"指针"的结果 到 cvvoid
"指向存储位置的开头,其中T
类型的对象驻留,就好像该对象是派生最多的对象一样 类型T
的对象 (1.8((即,不是基类子对象(。
这意味着您可以将指向类的指针转换为 void 指针。和。。。
§5.2.9 静态投射
10 可以显式使用">指向 cv
void
的指针"类型的右值 转换为指向对象类型的指针。指针类型的值 将对象转换为"指向 cvvoid
的指针"并返回到 原始指针类型将具有其原始值。
这意味着您可以使用 static_cast
将 void 指针转换回原始类指针。
希望对您有所帮助。祝你好运!
我在C++中没有看到太多的选角void*
。 这是 C 语言中在 C++ 中积极避免的做法。
转换为void*
会消除所有类型安全性。
如果使用 reinterpret_cast
或 static_cast
从指针类型强制转换为void*
,然后再转换回相同的指针类型,则标准实际上可以保证结果是明确定义的。
危险在于您可能会将void*
投射到错误的类型,因为您不再确定正确的类型是什么。
在C++中,你不需要静态强制转换来进入void*
:
int main()
{
CFoo* foo = new CFoo;
void* dt = foo;
tfunc(dt); // or tfunc(foo);
return 0;
}
注意:你对tfunc()
的实现非常正确,因为它确实需要强制转换。
我想知道这样做是否有任何陷阱/问题?
在将void*
转换回特定类型时,您需要绝对确定,否则,最终会导致未定义的行为和潜在的灾难。一旦使用void *
您将失去类型安全性。很难跟踪void *
实际指向的类型,无法保证或确定它确实指向要将其类型转换回的类型。
当我们投射到 void* 并再次返回时,有什么方法可以遇到错误或未定义的条件吗?
是的,#1
中提到的场景.
如果有这些问题,我们应该如何解决?
完全避免在C++中使用void *
,而是使用模板和继承。
在 C 语言中,在某些情况下,您可能绝对需要它,但尽量将其使用保持在最低限度。
底线,
C/C++允许您在脚上射击自己,这取决于您是否这样做。
标准唯一允许的是,给定A* pa
,(A*)(void*)pA == pA
。一个后果
void* pv = pA;
A* pA2 = (A*)pv;
pA2->anything ...
将与pA->anything ...
相同
其他一切都是"未定义的",广告 - 事实上 - 在某种程度上依赖于实现。
根据我的经验,以下是一些已知的陷阱:
- 考虑
A
派生形式B
、pA
和pB
是A*
和B*
。pB=pA
使pB
指向A
的底部。这并不意味着pB
和pA
是同一个地址。因此pB = (B*)(void*)pA
实际上可以将其他任何地方指向 A(尽管单个继承对象通常实现共享相同的来源,因此它显然工作正常( - 反之亦然:假设
pB
实际上指向一个A
,pA = (A*)(void*)pB
不一定正确地指向A对象。正确的方法是pA = static_cast<A*>(pB);
如果 - 以上几点可以与大多数单一继承实现一起使用,则永远不会适用于第一个以外的基数的多个不连续性:考虑
class A: public Z, public B { ... };
如果Z
不为空,给定一个A
,B
子组件将不具有相同的 A 地址。(C++中的多重继承无处不在( - 有时事情也取决于平台:
(char*)(void*)pI
(其中pI
指向整数(将与"*pI
如果*pI
in(-128..+127("不同(仅在小端序机器上(
一般来说,不要假设类型之间的转换只是改变了地址的解释方式。
我知道驱动程序等中的很多函数使用void指针将数据返回给调用方,架构大致相同:
int requestSomeData(int kindOfData, void * buffer, int bufferSize);
此函数可以采用不同的数据类型作为参数。他们所做的是使用 bufferSize 作为参数,以避免写入他们不应该写入的内存位置。如果 bufferSize 不匹配或小于应返回的数据,则该函数将返回错误代码。
无论如何:避免使用它们或在编写任何代码之前三思而后行。
这有效吗?
是的,根据标准 § 5.2.9.7 有效
类型为"指向 cv1 void 的指针"的 prvalue 可以转换为类型为"指向 cv2 T 的指针"的 prvalue,其中 T 是对象类型,cv2 与 cv1 具有相同的 cv 限定条件,或比 cv1 具有更高的 cv 限定条件。空指针值将转换为目标类型的空指针值。指向对象的指针类型的值转换为"指向 cv void 的指针"并返回,可能具有不同的 cv 限定,应具有其原始值。[ 示例:
T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2; // b will have the value true.
- 使用 [] 运算符时"binding reference of type discards qualifiers"
- 如何处理 c++ 中类实现中的"invalid use of non-static data member"?
- 在 QVector<std::unique_ptr 上使用 std::find<Type>>
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 使用 cmake 的 Linux 终端上的"Conversion to non-scalar type is requested"错误
- 控制到达非空函数clang(-Wreturn-type)的末尾
- 'string.assign(string.data(), 5)' 是明确定义的还是 UB?
- std::unordered_map 类型对象声明期间出现"field has incomplete type"错误
- 收到错误"invalid use of non-static data member 'stu::n' "
- 将系数存储在头文件的数组中("does not name a type"错误)
- C++ 初始化 .data 部分中的变量
- 模式"allocate memory or use existing data"
- boost::asio data owning `ConstBufferSequence`
- 尝试打开 ifstream 时出现"Incomplete type"错误
- "How to use long long data-type rather than pointers data-type to modify other variables ?"
- 我们可以在 c++ 中使用运算符重载添加 "User defined Datatype" + "Predefined Data Type"
- getaddrinfo() 返回错误"The requested name is valid, but no data of the requested type was found."
- Poco::Net::HTTPClientSession json data Content-Type not rece
- 修复警告"comparison is always false due to limited range of data type [-Wtype-limits]"
- 如何轻松初始化'double data type'为 -1 或 0 的第二个数组元素