The following construct in main() retrieves a class member's offset at runtime:
struct Base
{
virtual ~Base() = default;
};
struct Cls : public virtual Base
{
int a, b;
};
int main()
{
int Cls::* ptr = &Cls::a;
unsigned long offset = *reinterpret_cast<unsigned long*>(&ptr);
}
The class layout is determined at compile time and doesn't change. So, it would be beneficial to make this a constexpr.
Unfortunately, the above assignment requires an lvalue.
How can I get the same result using a constexpr?
Your class is not standard-layout. There is no way to obtain an offset to a member of a non-standard-layout class without undefined behavior (and therefore certainly not in a compile-time context) that is guaranteed to be supported by the standard, although see offsetof below.
Your approach is definitively UB per standard, even in a standard-layout class. It relies on very specific implementation details, assuming it works in the first place. (I haven't tested it.)
Since C++17 use of the offsetof macro is conditionally-supported (also in a compile-time context) for non-standard-layout classes. If the compiler does not support this, then what you want to do is impossible (except maybe via other compiler extensions), however all current compilers I am aware of support this, even if they emit warnings:
constexpr auto offset = offsetof(Cls, a);
(Before C++17 it was technically UB although the same practical consideration as above applies.)
But beware that layout in derived classes is not guaranteed to be consistent with virtual bases.
Found the solution myself:
template<class T> constexpr unsigned long Offset(T ptr)
{
return *reinterpret_cast<unsigned long*>(&ptr);
}
Related
I've been thinking why constexr and virtual are mutually exclusive, and someone added:
... constexpr is all about execution at compile time; if we're executing the function at compile time, we obviously know the type of data upon which it's acting at compile time as well, so late binding clearly isn't relevant.
However, it's possible that the dynamic type is not identical to the static type even in compile-time, and there might be cases where the dynamic type is needed:
class A {
public:
/* virtual */ constexpr int foo() {
return 1;
}
};
class B : public A {
public:
constexpr int foo() {
return 2;
}
};
constexpr int foo(A &a) {
// The static type is fixed here.
// What if we want to call B::foo() ?
return a.foo();
}
int main() {
B b;
constexpr int c = foo(b);
return 0;
}
That is, my question is
what's the (possible) rationale behind the standard prohibiting the combination of the two?
This restriction exists since constexpr was introduced in C++11:
10.1.5 The constexpr specifier [dcl.constexpr]
3 The definition of a constexpr function shall satisfy the following requirements:
(3.1) - it shall not be virtual;
But you're asking about rationale for this restriction, and not about the restriction itself.
The fact is, it may just be an oversight. Since in a constant expression the dynamic type of the object is required to be known, this restriction is unnecessary and artificial: This is what Peter Dimov and Vassil Vassilev assert in P1064R0, where they propose to remove it.
In fact, the wording for it no longer exists in the current draft.
Because virtual calls are resolved via vtables/RTTI (RunTime Type Information) located in the memory layout of your object at runtime, the "true type" behind the "used object handle" is not known at compile time.
In your example:
constexpr int foo(A &a) {
// The static type is fixed here.
// What if we want to call B::foo() ?
return a.foo();
}
If the foo member function is virtual there is no way for that foo function to be executed at compile time. And there is no point in marking a function as constexpr if it can never be executed at compile time. Hence there is no point in ever marking something both constexpr and virtual.
Now technically, depending on the code complexity, multiple cases might be resolvable by adding a completely new system (other than RTTI) to resolve virtual calls that would be compile time compatible (e.g some form of compiler meta data when everything is constexpr that remembers what type of instance you put in a pointer/reference) but that simply is not a thing right now.
If you want a runtime indirection (which is what virtual does) it doesn't make much sense to also want that to be executed at compile time.
P.S: sorry for the "compile time" and "runtime" spam.
Indeed, it is possible for compilers to know at compile time what is the dynamic type of a constant expression. This is a possibility, that is some time used by optimizer to devirtualize calls at compile time.
But the c++ language evolution take also in consideration how difficult it is to implement it in compilers. If such a consideration were not taken, then the c++ standard will be too far from the c++ coded so that it would be unusefull.
Maybe, it has been evaluated that keeping trac of the static type of every reference during constant expression evaluation would be too expensive to implement. This is where reality hurts!
I am trying to create a template class that contains a pointer to an arbitrary class instance and function as follows:
template<class C>
class A {
typedef void (C::*FunctPtr)(); //e.g. void C::some_funct();
FunctPtr functPtr_;
C* instPtr_;
public:
A(FunctPtr functPtr, C* instPtr)
: functPtr_(functPtr)
, instPtr_(instPtr) {}
};
However, I want to be able to create instances of this class without dynamic memory allocation using placement new. Does the C++ standard guarantee this template class is of fixed size for all classes C?
In Don Clugston's article on pointers I noticed a chart of the various sizes for member functions pointers on various compilers and a few compilers aren't always the same size. I thought I was hosed but is this standards compliant? From the C++ standard sec. 5.2.10 on Reinterpret cast:
— converting a prvalue of type “pointer to member function” to a different pointer to member function
type and back to its original type yields the original pointer to member value.
Would that statement from the C++ standard indicate member function pointers are all of the same size?
If not I suppose I could still rewrite the code as follows to take advantage of that reinterpret_cast guarantee explicitly:
class GenericClass;
template<class C>
class A {
typedef void (GenericClass::*GenFunctPtr)();
typedef void (C::*SpecificFunctPtr)();
GenFunctPtr functPtr_; //store any kind of function ptr in this fixed format
GenericClass* instPtr_;
public:
A(SpecificFunctPtr functPtr, C* instPtr)
: functPtr_(reinterpret_cast<GenFunctPtr>(functPtr))
, instPtr_(reinterpret_cast<GenericClass*>(instPtr)) {}
void DoSomething()
{
//now convert pointers back to the original type to use...
reinterpret_cast<SpecificFunctPtr>(functPtr_);
reinterpret_cast<C*>(instPtr_);
}
};
This now would seem to be required to be all the same size and yet be standards compliant, right? I'd prefer the first option however if I must the 2nd will also work. Thoughts?
I don't know if the implementation details of pointer-to-member are specified in the standard (can't find it), but since we know that C* will have the same size for all C, we can just determine the size of FunctPtr for various types C and just add a static_assert:
template <class C>
class A {
typedef void (C::*FunctPtr)(); //e.g. void C::some_funct();
static_assert(sizeof(FunctPtr) == 16,
"unexpected FunctPtr size"); // from coliru, clang and gcc
FunctPtr functPtr_;
C* instPtr_;
...
};
At least I tried this with several types of classes ({base, derived, multiple derived} x {virtual, non-virtual}) and it always gave the same size.
This is probably platform and/or compiler specific, as Pointers to member functions are very strange animals indicates:
The size of a pointer-to-member-function of a class that uses only single inheritance is just the size of a pointer.
The size of a pointer-to-member-function of a class that uses multiple inheritance is the size of a pointer plus the size of a size_t.
which is not what I see in clang or gcc.
Microsoft compilers use different sizes of member pointers depending on how complex the class is. Technically this isn't compliant (since you can define pointers to members even when the class definition isn't visible), but it works sufficiently well in practice that they do it by default. Pragmas and compiler switches are available to control this behaviour. See for example https://msdn.microsoft.com/en-us/library/83cch5a6.aspx.
Even so the pointers for any given class are always the same size, it's just different classes may have different sized pointers to members.
I would like to know if my following use of reinterpret_cast is undefined behaviour.
Given a template aggregate such as ...
template<typename T>
struct Container
{
Container(T* p) : ptr(p) { }
...
T* ptr;
};
... and a type hierarchy like ...
struct A { };
struct B : A { };
Is the following cast safe, given that B is a dynamic type of A ...
Container<B>* b = new Container<B>( new B() );
Container<A>* a = reinterpret_cast<Container<A>*>(b);
... in so far as that I can now safely use a->ptr and its (possibly virtual) members?
The code where I use this compiles and executes fine (Clang, OS X) but I'm concerned that I've placed a ticking bomb. I guess every instance of Container<T> shares the same layout and size so it shouldn't be a problem, right?
Looking at what cppreference.com says about reinterpret_cast, there seems to be a statement for legal use that covers what I'm trying to do ...
Type aliasing
When a pointer or reference to object of type T1 is reinterpret_cast (or C-style cast) to a pointer or reference to object of a different type T2, the cast always succeeds, but the resulting pointer or reference may only be accessed if both T1 and T2 are standard-layout types and one of the following is true:
...
T2 is an aggregate type or a union type which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions): this makes it safe to cast from the first member of a struct and from an element of a union to the struct/union that contains it.
I appreciate that it looks like I'm going the wrong way about this. That's not what I'm concerned about. I'd just like to know if what I'm doing is safe / legal or not. Thanks in advance for any help.
there seems to be a statement for legal use that covers what I'm trying to do ...
That's not what that exception says or means. That exception says that given
struct S { int i; } s;
you can use *reinterpret_cast<int *>(&s) to access s.i.
There is no similar exception for what you're trying to do. What you're trying to do is simply not valid in C++. Even the below is invalid:
struct S { int i; };
struct T { int i; };
int f(S s) { return ((T &) s).i; }
and compilers optimise based on the assumption that you don't write code like that.
For an actual example that fails at run-time with a current compiler:
#include <cstdlib>
struct S { int i; };
struct T { int i; };
void f(S *s, T *t) { int i = s->i; t->i++; if (s->i == i) std::abort(); }
Here, GCC optimises away the check s->i == i (GCC 4.9.2, with -O2 in the command-line options), and unconditionally calls std::abort(), because the compiler knows that s and t cannot possibly point to the same region of memory. Even though you might try to call it as
int main() { S s = { 0 }; f(&s, reinterpret_cast<T *>(&s)); }
Whether or not the type aliasing is legal according to the standard, you may have other issues.
I guess every instance of Container<T> shares the same layout and
size so it shouldn't be a problem, right?
Actually, not every instance of Container<T> shares the same layout! As explained in this question, template members are only created if they are used, so your Container<A> and Container<B> might have different memory layouts if different members are used for each type.
I've found a simple solution somewhere on the internet to an identity class without built-in C++ RTTI.
template <typename T>
class Identity {
public:
static int64_t id()
{
static int64_t dummy;
return reinterpret_cast<int64_t>(&dummy);
}
};
When we need some class ID, we just use:
Identity<OurClass>::id();
I'm wondering, are there any collisions? Can it return the same ID for the different classes, or the different ID for the same classes? I have tried this code with g++ with different optimization values, everything seems ok.
First off: there is such an integral type that is made specifically to contain pointers:
intptr_t
and in C++11 uintptr_t
Second, even though in practice on gcc they are equal, the size of a pointer to an object and the size of a function pointer (or pointer to member) might well be different. Therefore it would be better using a specific object rather than the method itself (for Standard conformance).
Third, it only gives you identity, while RTTI is much richer, as it knows about all the subclasses a given object can be cast to, and even allows cross-casts or casts across virtual inheritance.
Still, the corrected version can be useful I guess:
struct Foo {
static intptr_t Id() {
static boost::none_t const Dummy = {};
return reinterpret_cast<intptr_t>(&Dummy);
}
};
And in hierarchies, having a virtual function returning that ID.
For completeness, I'll mention that Clang and LLVM have their own way of dealing with object identification without RTTI. You may want to read about their way of implementing isa, cast and dyn_cast here.
This solution casts a function pointer to an int. There is no guarantee that this pointer fits into an int, although in practice sizeof(void *) == sizeof(void (*)()) <= sizeof(int)
Edit: My bad. On x86_64 sizeof(int) = 4, sizeof(void (*)()) = 8, so collisions are possible and are unpredictable.
You can cast to an integral of appropriate size, but still it is undefined behavior theoretically.
This version avoids undefined behavior (and compiler warnings):
template <typename T>
class Identity {
public:
static const int* id() { static const int id = 0; return &id; }
};
I have some code that implements a kind of run-time reflection. In order to get a pointer to a field of a class inside a given instance, i basically take the pointer to the class instance and add a fixed offset that is calculated once for each field that is exposed to the reflection library.
I kept the implementation quite simple, since i didn't need to support multiple inheritance and i made the mistake of not taking into account that, even with single inheritance, this situation is possible:
class A
{
public:
unsigned int m_uiField;
};
class B : public A
{
virtual void VirtualMethod()
{
}
};
int main()
{
unsigned int uiOffsetA(reinterpret_cast<unsigned int>(&(reinterpret_cast<A *>(0)->m_uiField)));
// uiOffsetA is 0 on VC9
unsigned int uiOffsetB(reinterpret_cast<unsigned int>(&(reinterpret_cast<B *>(0)->m_uiField)));
// uiOffsetB is 4 on VC9
}
In this case the virtual table pointer that my compiler puts at the beginning of each instance of B was offsetting by 4 bytes the fields of A.
My first idea was to do something similar to what i'm doing for the field offsets and store a single unsigned int as an offset for the base class to add to pointers to derived class instances together with the field offset. So, at initialization time i call this function one for each Derived class inheriting from a Base class:
template <typename Base, typename Derived>
unsigned int GetBaseClassOffset()
{
Derived *pDerived(reinterpret_cast<Derived *>(4));
Base *pBase(pDerived);
assert(pBase >= pDerived);
return reinterpret_cast<unsigned int>(pBase) - reinterpret_cast<unsigned int>(pDerived);
}
And everything seems to work with my tests using VC9.
But then it came to my mind that this area of C++ could be implementation dependent, and that other things like alignment could break this up.
In the end my question is:
Can i assume that fields of a base class will always be positioned at a constant positive offset relative to a pointer to a derived class instance?
Note: i am not saying "constant across all compilers", i will use some code (eventually compiler dependent) to detect this offset at startup.
For this situation, you can use pointer-to-members:
See it live: http://ideone.com/U4w7j
struct A
{
unsigned int m_uiField;
};
struct B : A
{
virtual void VirtualMethod() { }
};
int main()
{
A instance_a;
B instance_b;
unsigned int A::* ptrA = &A::m_uiField;
unsigned int B::* ptrB = &B::m_uiField;
// application:
unsigned int value = instance_a.*ptrA;
value = instance_b.*ptrA;
//value = instance_a.*ptrB; // incompatible types
value = instance_b.*ptrB;
// also:
A* dynamic = new B();
value = dynamic->*ptrA; // etc
}
I suggest you also look at template metaprogramming features (part of TR1 and C++11 now:), notably the is_pod type trait:
http://publib.boulder.ibm.com/infocenter/comphelp/v9v111/index.jsp?topic=/com.ibm.xlcpp9.aix.doc/standlib/header_type_traits.htm
http://www.boost.org/doc/libs/1_47_0/libs/type_traits/doc/html/boost_typetraits/reference/is_pod.html
http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.1/structstd_1_1tr1_1_1is__pod.html
http://msdn.microsoft.com/en-us/library/bb982918(v=VS.100).aspx
This is important because using offsetof on anything else is hazardous.
Standard-conformant implementation of reflection in C++ (including C++11) is not possible. Mainly because member offset is not standardized and so depends of compiler. It depends on polimorphism implementation, on alignment and probably on other things.
You can implement reflection for specific compiler, or for limited range of classes.
Much more info about C++ reflection is here.
Reflection support was proposed for C++11 standard but was postponed because required much more time.
Can i assume that fields of a base class will always be positioned at a constant positive offset relative to a pointer to a derived class instance?
No, you can't. Why is that a possitive offset? I would expect that in common implementations base members are placed before the derived classes?
Note the standard 'operator' (well not quite) offsetof, which will give you the offset from a struct to a member. It's usually implemented as a macro similar to yours, derreferencing the null pointer. It probably won't help you since its guaranteed to work only with POD type classes. See 18.2/4 at the standard:
The macro offsetof(type, member-designator) accepts a restricted set of type arguments in this International
Standard. If type is not a standard-layout class (Clause 9), the results are undefined.