reinterpret_cast 输入到 std::unique_ptr 永远不会真正安全吗?
Is it never truly safe to reinterpret_cast input into std::unique_ptr?
当使用具有可变大小结构的各种 API 时(必须分配为 byte[] 然后转换为结构的结构),如果 unique_ptr 持有者可以指向结构,因为这就是我们将要使用的。
示例:
std::unique_ptr<VARIABLE_SIZE_STRUCT[]> v;
v.reset(reinterpret_cast<VARIABLE_SIZE_STRUCT*>(new BYTE[bytesRequired]));
这允许 `v 提供结构本身的视图,这是更可取的,因为我们不需要第二个变量,除了删除之外我们不关心字节指针。
问题在于可能会在强制转换上对指针进行 thunk(使其释放不安全)。我看不出为什么编译器会在 cast 上更改指针值(因为没有继承),但我听说标准保留对任何 cast 上的任何指针进行 thunk 的权利,就符合标准的编码而言,这办法是出window吧?或者有什么理由是安全的?有没有办法至少 static_assert 这样做,或者有其他方法可以安全或干净地处理这种类型的结构?
你是对的,这是不安全的。但是,可以使其安全。
标准保证如果你reinterpret_cast
到一个不同的类型,然后回到原来的类型,你会得到原来的值。
您可以将它与自定义删除器一起使用,以确保您的内部指针被转换回释放它之前分配的类型。
auto deleter = [](VARIABLE_SIZE_STRUCT* ptr)
{
delete[] reinterpret_cast<uint8_t*>(ptr);
};
std::unique_ptr<VARIABLE_SIZE_STRUCT, decltype(deleter)> v
(reinterpret_cast<VARIABLE_SIZE_STRUCT*>(new uint8_t[256]), deleter);
此时,您最好创建自己的包装器而不是使用 unique_ptr
。
您的分配可能没有 VARIABLE_SIZE_STRUCT
所需的对齐方式
分配的内存中没有 VARIABLE_SIZE_STRUCT 放置的对象 - new
ed - 假设你处理了它,unique_ptr
默认析构函数逻辑应该找到要销毁的预期对象实例,但是释放本身将不会在 BYTE*
上使用 delete []
完成 - 要定义行为,您必须首先自定义要调用的删除器~VARIABLE_SIZE_STRUCT()
然后 delete[]
...
如果您担心 "thunking",您可以在 运行 时间进行检查:
BYTE* p;
v.reset(reinterpret_cast<VARIABLE_SIZE_STRUCT*>(p = new BYTE[bytesRequired]));
assert(reinterpret_cast<BYTE*>(v.get()) == p);
5.2.10/7 的背景:
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast<cvT*>(static_cast<cv void*>(v))
. Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than
those of T1) and back to its original type yields the original pointer value.
因此,如果 VARIABLE_SIZE_STRUCT
的对齐要求比 BYTE
的对齐要求更严格,则无法保证 使用 [=] 检索原始指针21=].
当使用具有可变大小结构的各种 API 时(必须分配为 byte[] 然后转换为结构的结构),如果 unique_ptr 持有者可以指向结构,因为这就是我们将要使用的。
示例:
std::unique_ptr<VARIABLE_SIZE_STRUCT[]> v;
v.reset(reinterpret_cast<VARIABLE_SIZE_STRUCT*>(new BYTE[bytesRequired]));
这允许 `v 提供结构本身的视图,这是更可取的,因为我们不需要第二个变量,除了删除之外我们不关心字节指针。
问题在于可能会在强制转换上对指针进行 thunk(使其释放不安全)。我看不出为什么编译器会在 cast 上更改指针值(因为没有继承),但我听说标准保留对任何 cast 上的任何指针进行 thunk 的权利,就符合标准的编码而言,这办法是出window吧?或者有什么理由是安全的?有没有办法至少 static_assert 这样做,或者有其他方法可以安全或干净地处理这种类型的结构?
你是对的,这是不安全的。但是,可以使其安全。
标准保证如果你reinterpret_cast
到一个不同的类型,然后回到原来的类型,你会得到原来的值。
您可以将它与自定义删除器一起使用,以确保您的内部指针被转换回释放它之前分配的类型。
auto deleter = [](VARIABLE_SIZE_STRUCT* ptr)
{
delete[] reinterpret_cast<uint8_t*>(ptr);
};
std::unique_ptr<VARIABLE_SIZE_STRUCT, decltype(deleter)> v
(reinterpret_cast<VARIABLE_SIZE_STRUCT*>(new uint8_t[256]), deleter);
此时,您最好创建自己的包装器而不是使用 unique_ptr
。
您的分配可能没有
VARIABLE_SIZE_STRUCT
所需的对齐方式
分配的内存中没有 VARIABLE_SIZE_STRUCT 放置的对象 -
new
ed - 假设你处理了它,unique_ptr
默认析构函数逻辑应该找到要销毁的预期对象实例,但是释放本身将不会在BYTE*
上使用delete []
完成 - 要定义行为,您必须首先自定义要调用的删除器~VARIABLE_SIZE_STRUCT()
然后delete[]
...
如果您担心 "thunking",您可以在 运行 时间进行检查:
BYTE* p;
v.reset(reinterpret_cast<VARIABLE_SIZE_STRUCT*>(p = new BYTE[bytesRequired]));
assert(reinterpret_cast<BYTE*>(v.get()) == p);
5.2.10/7 的背景:
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is
static_cast<cvT*>(static_cast<cv void*>(v))
. Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value.
因此,如果 VARIABLE_SIZE_STRUCT
的对齐要求比 BYTE
的对齐要求更严格,则无法保证 使用 [=] 检索原始指针21=].