指向对象开头的指针 (C++)
我需要一种方法来获取指向 C++ 中对象开头的指针。该对象在模板内部使用,因此它可以是任何类型(多态或非多态),并且可能是使用多重继承的对象。
我发现 这篇文章 描述了一种方法(请参阅名为“动态如果 T 是多态类型,则使用 typeid 和dynamic_cast 将其强制转换为 void*。
这在 MSVC 上运行得很好,但是在 GCC (4.x) 上,当它与非多态类型一起使用时,它似乎会失败并抛出编译器错误。
有谁知道一种方法:
- 使 GCC 表现良好,并正确评估 typeid
- 或者另一种方法来做到这一点,它将在 GCC 上编译
下面是我当前用来尝试实现此目的的代码。
template <typename T>
void* dynamicCastToVoidPtr(T *const ptr)
{
// This is done using a separate function to avoid a compiler error on some
// compilers about non-polymorphic types when calling startOfObject
return dynamic_cast<void*>(ptr);
}
template <typename T>
void* startOfObject(T *const ptr)
{
// In cases of multiple inheritance, a pointer may point to an offset within
// another object
// This code uses a dynamic_cast to a void* to ensure that the pointer value
// is the start of an object and not some offset within an object
void *start = static_cast<void*>(ptr);
if(start)
typeid(start = dynamicCastToVoidPtr(ptr), *ptr);
return start;
}
template <typename T>
void doSomethingWithInstance(T *const instance)
{
// Here is where I need to get a void* to the start of the object
// You can think of this as the deleteInstance function of my memory pool
// where the void* passed into freeMemory should point to the
// start of the memory that the memory pool returned previously
void *start = startOfObject(instance);
if(start)
allocator->freeMemory(start);
}
谢谢。
I need a way to get a pointer to the start of an object in C++. This object is used inside a template so it can be any type (polymorphic or not) and could potentially be an object that uses multiple inheritance.
I found this article which describes a way to do it (see the section called "Dynamic Casts") using typeid and a dynamic_cast to void* in the case that T is a polymorphic type.
This works perfectly well on MSVC, however on GCC (4.x) it seems to fall on its arse and spits out a compiler error when it is used with a non-polymorphic type.
Does anyone know a way to:
- Make GCC behave itself, and evaluate typeid correctly
- Or another way to do this, that will compile on GCC
Below is the code I am currently using to try and achieve this.
template <typename T>
void* dynamicCastToVoidPtr(T *const ptr)
{
// This is done using a separate function to avoid a compiler error on some
// compilers about non-polymorphic types when calling startOfObject
return dynamic_cast<void*>(ptr);
}
template <typename T>
void* startOfObject(T *const ptr)
{
// In cases of multiple inheritance, a pointer may point to an offset within
// another object
// This code uses a dynamic_cast to a void* to ensure that the pointer value
// is the start of an object and not some offset within an object
void *start = static_cast<void*>(ptr);
if(start)
typeid(start = dynamicCastToVoidPtr(ptr), *ptr);
return start;
}
template <typename T>
void doSomethingWithInstance(T *const instance)
{
// Here is where I need to get a void* to the start of the object
// You can think of this as the deleteInstance function of my memory pool
// where the void* passed into freeMemory should point to the
// start of the memory that the memory pool returned previously
void *start = startOfObject(instance);
if(start)
allocator->freeMemory(start);
}
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
gcc 的确切错误消息是
这可以通过使用
boost::is_polymorphic
结合boost::enable_if
和boost::disable_if
来处理,不幸的是 gcc 阻塞使用显而易见的方法,所以这里是解决方法:我们使用 SFINAE 发挥我们的优势(省略号始终被认为是重载决策中的最后一个,因此编译器首先尝试使用
dynamic_cast
版本,该版本对于非多态性失败类型,因为enable_if
)。我在 gcc 3.4 上测试过,它通过了。我正在调查 另一个问题 为什么使用 < code>disable_if 而不是
...
不起作用。编辑:
这是一个简单的拼写错误(忘记了
::type
位):The exact error message by gcc is
This could be handled by using
boost::is_polymorphic
in combination withboost::enable_if
andboost::disable_if
, unfortunately gcc chokes with the obvious approach, so here is the workaround:Where we use SFINAE at our advantage (the ellipsis is always considered last in overload resolution so the compiler first attempts to use the
dynamic_cast
version which fails for non polymorphic types because ofenable_if
).I've test it on gcc 3.4 and it passed. I'm investigating in another question why using
disable_if
instead of...
doesn't work.EDIT:
and it was a simple typo (forgot the
::type
bit):我做了一些调查,您可能在这里发现了 GCC 中的一个错误;我会举报。然而,可能有一些我找不到的规则表明,在这种情况下,逗号运算符左侧的模板函数确实需要实例化,即使整个表达式没有被评估;在这种情况下,本文中的技术就是错误的。
我建议你看看 boost ::type_traits::is_polymorphic 可以为您服务。
I did some investigation, and you may have found a bug in GCC here; I would report it. However, there may be some rule I can't find that says that the template function on the left side of the comma operator does need to be instantiated in this case, even though the overall expression is not evaluated; in that case the technique in the article is just wrong.
I suggest you see if boost::type_traits::is_polymorphic can be made to work for you.
我从另一个问题找到了一个解决方案,可以让我在编译时解决如果类型是多态的,那么我可以将其与模板专业化一起使用,以使用正确的类型转换。显然,如果编译器在子对象之间添加填充,则此方法可能会中断,但我希望可以在某些已知情况下添加一些编译时断言来捕获这一点。它在 MSVC 和 GCC 上都能正确编译和运行。
这是计算类型是否是多态的代码。
根据类型是否多态执行转换的代码。
以及它的测试用例。
I've found a solution from another question that lets me work out at compile time if a type is polymorphic and I can then use this with template specialisation to use the correct type of cast. Apparently this method might break if the compiler adds padding between sub-objects, but I can hopefully add some compile time asserts on some known cases to catch that. It does compile and run correctly on both MSVC and GCC.
This is the code to work out if a type is polymorphic.
The code to perform the casting based on whether the type is polymorphic.
And a test case for it.