What would be a decent approach to check at compile/run-time that a particular struct/class does not have any virtual functions. This check is required in order to ensure the proper byte alignment when doing placement new.
Having so much as a single virtual function will shift the entire data by a vtable pointer size, which will completely mess things up in conjunction with the placement new operator.
Some more details: I need something that works across all major compiler and platforms, e.g. VS2005, VC++10, GCC 4.5, and Sun Studio 12.1 on top of Windows, Linux, and Solaris.
Something that is guaranteed to work with the following scenario should suffice:
struct A { char c; void m(); };
struct B : A { void m(); };
Should someone decide to make this change:
struct A { char c; virtual void m(); };
struct B : A { void m(); };
It would be great to see a compile-time error that says struct A must not contain virtual functions.
There are facilities and tricks (depending on the version of C++ you are using) to get the proper alignment for a class.
In C++0x, the alignof command is similar to sizeof but returns the required alignment instead.
In C++03, the first thing to note is that the size is a multiple of the alignment, because elements need be contiguous in an array. This means that using the size as the alignment is over-zealous (and may waste space) but works fine. With some trickery you can get a better value:
template <typename T>
struct AlignHelper
{
T t;
char c;
};
template <typename T>
struct Alignment
{
static size_t const diff = sizeof(AlignHelper<T>) - sizeof(T);
static size_t const value = (diff != 0) ? diff : sizeof(T);
};
This little helper gives a correct alignment as a compile-time constant (suitable for template programming therefore). It may be larger than the minimal alignment required (*).
Normally though it should be fine to use placement new, unless you are actually using it on a "raw buffer". In this case, the size of the buffer should be determined with the following formula:
// C++03
char buffer[sizeof(T) + alignof(T) - 1];
Or you should make use of C++0x facilities:
// C++0x
std::aligned_storage<sizeof(T), alignof(T)> buffer;
Another trick to ensure a "right" alignment for virtual tables it to make use of the union:
// C++03 and C++0x
union { char raw[sizeof(T)]; void* aligner; } buffer;
The aligner parameter guarantees that the buffer is correctly aligned for pointers, and thus for virtual tables pointers as well.
EDIT: Additional explanations as suggested by #Tony.
(*) How does this work ?
To understand it we need to delve into the memory representation of a class. Each subelement of a class has its own alignment requirement, so for example:
struct A { int a; char b; int c; };
+----+-+---+----+
| a |b|xxx| c |
+----+-+---+----+
Where xxx denotes padding added so that c is suitably aligned.
What is the alignment of A ? Generally speaking, it is the stricter alignment of the subelements, so here, the alignment of int (which is often 4 since int is often a 32 bits integral).
To "guess" the alignment of an arbitrary type, we thus "trick" the compiler by using the AlignHelper template. Remember that sizeof(AlignHelper<T>) must be a multiple of the alignment because types should be laid out contiguously in an array, thus we hope our type will be padded after the c attribute, and the alignment will be the size of c (1 by definition) plus the size of the padding.
// AlignHelper<T>
+----------------+-+---+
| t |c|xxx|
+----------------+-+---+
// T
+----------------+
| t |
+----------------+
When we do sizeof(AlignHelper<T>) - sizeof(T) we get this difference. Surprisingly though, it could be 0.
The issue comes from the fact that if there is some padding (unused bytes) at the end of T, then a smart compiler could decide to stash c there, and thus the difference of size would be 0.
We could, obviously, try to recursively increase the size of c attribute (using a char array), until we finally get a non-zero difference. In which case we would get a "tight" alignment, but the simplest thing to do is to bail out and use sizeof(T), since we already know it is a multiple of the alignment.
Finally, there is no guarantee that the alignment we get with this method is the alignment of T, we get a multiple of it, but it could be bigger, since sizeof is implementation dependent and a compiler could decide to align all types on power of 2 boundaries, for example.
What would be a decent approach to
check at compile/run-time that a
particular struct/class does not have
any virtual functions
template<typename T>
struct Is_Polymorphic
{
struct Test : T { virtual ~Test() = 0; };
static const bool value = (sizeof(T) == sizeof(Test));
};
Above class can help you to check if the given class is polymorphic or not at compile time. [Note: virtual inheritance also have a vtable included]
You are almost certainly doing something wrong.
However, given that you have decided to do something wrong, you don't want to know if your tpe has no virtual functions. You want to know if it is okay to treat your type as an array of bytes.
In C++03, is your type POD? As luck would have it, there's a trait for that, aptly named is_pod<T>. This is provided by Boost/TR1 in C++03, although it requires a relatively modern compiler [gcc > 4.3, MSVC > 8, others I don't know].
In C++11, you can ease up your requirements by asking if your type is trivially copiable. Again, there's a trait for that: is_trivially_copyable<T>.
In either case, there is also is_polymorphic<T>, but as I said, that's really not what you want anyhow. If you are using an older compiler, it does have the advantage of working out of the box if you get it from Boost; it performs the sizeof test mentioned elsewhere, rather than simply reporting false for all user defined types as is the case with is_pod.
No matter what, you'd better be 120% sure your constructor is a noop; that's not something that can be verified.
I just saw your edit. Of what you listed, Sun Studio is the only one that might not have the necessary intrinsics for these traits to work. gcc and MSVC have both had them for several years now.
dynamic_cast is only allowed for polymorphic classes, so you can utilize that for a compile time check.
Use is_pod type trait from tr1?
There is no feature for you to determine whether a class has virtual functions are not.
Related
I have a very big class with a bunch of members, and I want to initialize them with a given specific value.The code below is the most naive implementation, but I don't like it since it's inelegant and hard to maintain because I have to list all the members in the constructor.
struct I_Dont_Like_This_Approach {
int foo;
long bar;
unsigned baz;
int a;
int b;
int c;
int d;
SomeStruct and_so_on;
/*...*/
public:
explicit I_Dont_Like_This_Approach(int i) : foo(i), bar(i), baz(i), a(i), b(i), c(i), d(i), and_so_on(i) /*...*/ {}
};
I thought of an alternative implementation using templates.
template <int N>
struct MyBigClass {
int foo{N};
long bar{N};
unsigned baz{N};
int a{N};
int b{N};
int c{N};
int d{N};
SomeStruct and_so_on{N};
/*...*/
};
but I'm not sure if the code below is safe.
MyBigClass<1> all_one;
MyBigClass<2> all_two;
/* Is the following reinterpret_cast safe? */
all_one = reinterpret_cast<decltype(all_one) &>(all_two);
Does the C++ specification have any guarantees about the data layout compatibility of such templated structs? Or is there a more reasonable implementation? (in standard C++, and don't use macros)
I would argue that the first one is much more maintainable, with the right warnings enabled (and a modern compiler), you will see if your initializer list gets out of sync with the class fields at compile time.
As to your alternative.. you're using templates as compiler arguments, which is not what they're meant to be. That brings a whole slew of issues:
instantiated templates get copied in memory, making your executable larger. Though in this case, I'm hoping your compiler is smart enough to see that the field structure is the same and treat it as one type.
your code now works only with constant literal integers, no more run-time variables.
there is indeed no guarantee that the memory structure of those two classes is the same. You can disable optimizations in most compilers (like pack, alignment, etc), but that comes at the cost of disabling optimizations, which isn't actually necessary except to support your specific code.
And related to the last one, if you ever need to consider whether this is ever going to break, you're heading down a very dark road. I mean any sane person can tell you it will "probably work", but the fact that you have no guarantees in the language that pretty much popularized memory corruption and buffer overflows should terrify you. Write constructors.
Following a snippet of code from Loki singleton implementation which shows what it calls "MaxAlign Trick". I assume it has something to do with alignment (duh!), but what's the purpose of trying to align with all the types mentioned inside the union? Will the placement new inside Create() break without it?
template <class T> struct CreateStatic
{
union MaxAlign
{
char t_[sizeof(T)];
short int shortInt_;
int int_;
long int longInt_;
float float_;
double double_;
long double longDouble_;
struct Test;
int Test::* pMember_;
int (Test::*pMemberFn_)(int);
};
static T* Create()
{
static MaxAlign staticMemory_;
return new(&staticMemory_) T;
}
// other code...
}
MaxAlign serves two purposes. First, it is an implementation of the C++11 std::max_align_t: "a trivial standard-layout type whose alignment requirement is at least as strict (as large) as that of every scalar type." (cppreference). Since the alignment of a type is the alignment of the data member with the highest alignment requirements, the definition of MaxAlign gives us exactly that: a type that is guaranteed to have the max. alignment for the platform of interest.
Second, it is also a buffer that is large enough to contain a T:
char t_[sizeof(T)];
Taking both aspects, MaxAlign provides the C++11 feature std::aligned_storage_t<size, alignment> (without taking over-alignment of T is into account - it probably didn't even exist back then).
But why is it needed: placement new requires the buffer to be suitably aligned for the instance that is being constructed. Without this "alignment trick", you might end up with undefined behaviour. T being an unkonwn type, Loki circumvents any risks by choosing the maximal alignment for the platform the code is being compiled for.
In modern code, you would probably not use placement new, but use a static object on the stack, e.g.
static T& Create() {
static T instance;
return instance;
}
But 20 years ago, this might not have worked properly across compilers and/or in multi-threaded environments (proper initialisation of T instance in the above is only guaranteed since C++11 IIRC).
Is this legal in c++11? Compiles with the latest intel compiler and appears to work, but I just get that feeling that it is a fluke.
class cbase
{
virtual void call();
};
template<typename T> class functor : public cbase
{
public:
functor(T* obj, void (T::*pfunc)())
: _obj(obj), _pfunc(pfunc) {}
virtual void call()
{
(_obj)(*_pfunc)();
}
private:
T& _obj;
void (T::*_pfunc)();
//edited: this is no good:
//const static int size = sizeof(_obj) + sizeof(_pfunc);
};
class signal
{
public:
template<typename T> void connect(T& obj, void (T::*pfunc)())
{
_ptr = new (space) functor<T>(obj, pfunc);
}
private:
cbase* _ptr;
class _generic_object {};
typename aligned_storage<sizeof(functor<_generic_object>),
alignment_of<functor<_generic_object>>::value>::type space;
//edited: this is no good:
//void* space[(c1<_generic_object>::size / sizeof(void*))];
};
Specifically I'm wondering if void* space[(c1<_generic_object>::size / sizeof(void*))]; is really going to give the correct size for c1's member objects (_obj and _pfunc). (It isn't).
EDIT:
So after some more research it would seem that the following would be (more?) correct:
typename aligned_storage<sizeof(c1<_generic_object>),
alignment_of<c1<_generic_object>>::value>::type space;
However upon inspecting the generated assembly, using placement new with this space seems to inhibit the compiler from optimizing away the call to 'new' (which seemed to happen while using just regular '_ptr = new c1;'
EDIT2: Changed the code to make intentions a little clearer.
const static int size = sizeof(_obj) + sizeof(_pfunc); will give the sum of the sizes of the members, but that may not be the same as the size of the class containing those members. The compiler is free to insert padding between members or after the last member. As such, adding together the sizes of the members approximates the smallest that object could possibly be, but doesn't necessarily give the size of an object with those members.
In fact, the size of an object can vary depending not only on the types of its members, but also on their order. For example:
struct A {
int a;
char b;
};
vs:
struct B {
char b;
int a;
};
In many cases, A will be smaller than B. In A, there will typically be no padding between a and b, but in B, there will often be some padding (e.g., with a 4-byte int, there will often be 3 bytes of padding between b and a).
As such, your space may not contain enough...space to hold the object you're trying to create there in init.
I think you just got lucky; Jerry's answer points out that there may be padding issues. What I think you have is a non-virtual class (i.e., no vtable), with essentially two pointers (under the hood).
That aside, the arithmetic: (c1<_generic_object>::size / sizeof(void*)) is flawed because it will truncate if size is not a multiple of sizeof(void *). You would need something like:
((c1<_generic_object>::size + sizeof(void *) - 1) / sizeof(void *))
This code does not even get to padding issues, because it has a few of more immediate ones.
Template class c1 is defined to contain a member T &_obj of reference type. Applying sizeof to _obj in scope of c1 will evaluate to the size of T, not to the size of reference member itself. It is not possible to obtain the physical size of a reference in C++ (at least directly). Meanwhile, any actual object of type c1<T> will physically contain a reference to T, which is typically implemented in such cases as a pointer "under the hood".
For this reason it is completely unclear to me why the value of c1<_generic_object>::size is used as a measure of memory required for in-pace construction of an actual object of type c1<T> (for any T). It just doesn't make any sense. These sizes are not related at all.
By pure luck the size of an empty class _generic_object might evaluate to the same (or greater) value as the size of a physical implementation of a reference member. In that case the code will allocate a sufficient amount of memory. One might even claim that the sizeof(_generic_object) == sizeof(void *) equality will "usually" hold in practice. But that would be just a completely arbitrary coincidence with no meaningful basis whatsoever.
This even looks like red herring deliberately inserted into the code for the purpose of pure obfuscation.
P.S. In GCC sizeof of an empty class actually evaluates to 1, not to any "aligned" size. Which means that the above technique is guaranteed to initialize c1<_generic_object>::size with a value that is too small. More specifically, in 32 bit GCC the value of c1<_generic_object>::size will be 9, while the actual size of any c1<some_type_t> will be 12 bytes.
Is the following legal C++ with well-defined behaviour?
class my_class { ... };
int main()
{
char storage[sizeof(my_class)];
new ((void *)storage) my_class();
}
Or is this problematic because of pointer casting/alignment considerations?
Yes, it's problematic. You simply have no guarantee that the memory is properly aligned.
While various tricks exist to get storage with proper alignment, you're best off using Boost's or C++0x's aligned_storage, which hide these tricks from you.
Then you just need:
// C++0x
typedef std::aligned_storage<sizeof(my_class),
alignof(my_class)>::type storage_type;
// Boost
typedef boost::aligned_storage<sizeof(my_class),
boost::alignment_of<my_class>::value>::type storage_type;
storage_type storage; // properly aligned
new (&storage) my_class(); // okay
Note that in C++0x, using attributes, you can just do this:
char storage [[align(my_class)]] [sizeof(my_class)];
As people have mentioned here, this won't necessarily work due to alignment restrictions. There are several ways to get the alignment right. First, if you have a C++0x-compliant compiler, you can use the alignof operator to try to force the alignment to be correct. Second, you could dynamically-allocate the character array, since memory from operator new is guaranteed to be aligned in such a way that anything can use it correctly. Third, you could try storing the character array in a union with some type that has the maximum possible alignment on your system; I believe that this article has some info on it (though it's designed for C++03 and is certainly not as good as the alignof operator that's coming out soon).
Hope this helps!
It is at least problematic due to alignment.
On most Non-Intel architecture the code will generate a "bus error" due to wrong alignment or be extremely slow because of processor traps needed to fix the unaligned memory access.
On Intel architecture this will normally just be a bit slower than usual. Except if some SSE operations are involved, then it may also crash.
In case anyone wants to avoid Boost or C++1x, this complete code works both in GCC and MSVC. The MSVC-specific code is based on Chromium's aligned_memory.h. It's a little more complex than the GCC version, because MSVC's __declspec(align(.)) only accepts literal alignment values, and this is worked around using template specialization for all possible alignments.
#ifdef _MSC_VER
template <size_t Size, size_t Align>
struct AlignedMemory;
#define DECLARE_ONE_ALIGNED_MEMORY(alignment) \
template <size_t Size> \
struct __declspec(align(alignment)) AlignedMemory<Size, alignment> { \
char mem[Size]; \
};
DECLARE_ONE_ALIGNED_MEMORY(1)
DECLARE_ONE_ALIGNED_MEMORY(2)
DECLARE_ONE_ALIGNED_MEMORY(4)
DECLARE_ONE_ALIGNED_MEMORY(8)
DECLARE_ONE_ALIGNED_MEMORY(16)
DECLARE_ONE_ALIGNED_MEMORY(32)
DECLARE_ONE_ALIGNED_MEMORY(64)
DECLARE_ONE_ALIGNED_MEMORY(128)
DECLARE_ONE_ALIGNED_MEMORY(256)
DECLARE_ONE_ALIGNED_MEMORY(512)
DECLARE_ONE_ALIGNED_MEMORY(1024)
DECLARE_ONE_ALIGNED_MEMORY(2048)
DECLARE_ONE_ALIGNED_MEMORY(4096)
#else
template <size_t Size, size_t Align>
struct AlignedMemory {
char mem[Size];
} __attribute__((aligned(Align)));
#endif
template <class T>
struct AlignedMemoryFor : public AlignedMemory<sizeof(T), __alignof(T)> {};
The char array may not be aligned correctly for the size of myclass. On some architectures, that means slower accesses, and on others, it means a crash. Instead of char, you should use a type whose alignment is equal to or greater than that of the struct, which is given by the largest alignment requirement of any of its members.
#include <stdint.h>
class my_class { int x; };
int main() {
uint32_t storage[size];
new(storage) my_class();
}
To allocate enough memory for one my_class instance, I think size ought to be sizeof(my_class) / sizeof(T), where T is whichever type you use to get the correct alignment.
Is it possible to write a C++ class or struct that is fully compatible with C struct. From compatibility I mean size of the object and memory locations of the variables. I know that its evil to use *(point*)&pnt or even (float*)&pnt (on a different case where variables are floats) but consider that its really required for the performance sake. Its not logical to use regular type casting operator million times per second.
Take this example
Class Point {
long x,y;
Point(long x, long y) {
this->x=x;
this->y=y;
}
float Distance(Point &point) {
return ....;
}
};
C version is a POD struct
struct point {
long x,y;
};
The cleanest was to do this is to inherit from the C struct:
struct point
{
long x, y;
};
class Point : public struct point
{
public:
Point(long x, long y)
{ this->x=x; this->y=y; }
float Distance(Point &point)
{ return ....; }
}
The C++ compiler guarantees the C style struct point has the same layout as with the C compiler. The C++ class Point inherits this layout for its base class portion (and since it adds no data or virtual members, it will have the same layout). A pointer to class Point will be converted to a pointer to struct point without a cast, since conversion to a base class pointer is always supported. So, you can use class Point objects and freely pass pointers to them to C functions expecting a pointer to struct point.
Of course, if there is already a C header file defining struct point, then you can just include this instead of repeating the definition.
Yes.
Use the same types in the same order in both languages
Make sure the class doesn't have anything virtual in it (so you don't get a vtable pointer stuck on the front)
Depending on the compilers used you may need to adjust the structure packing (usually with pragmas) to ensure compatibility.
(edit)
Also, you must take care to check the sizeof() the types with your compilers. For example, I've encountered a compiler that stored shorts as 32 bit values (when most will use 16). A more common case is that an int will usually be 32 bits on a 32-bit architecture and 64 bits on a 64-bit architecture.
POD applies to C++. You can have member functions. "A POD type in C++ is an aggregate class that contains only POD types as members, has no user-defined destructor, no user-defined copy assignment operator, and no nonstatic members of pointer-to-member type"
You should design your POD data structures so they have natural alignment, and then they can be passed between programs created by different compilers on different architectures. Natural alignment is where the memory offset of any member is divisible by the size of that member. IE: a float is located at an address that is divisible by 4, a double is on an address divisible by 8. If you declare a char followed by a float, most architectures will pad 3 bytes, but some could conceivably pad 1 byte. If you declare a float followed by a char, all compilers (I ought to add a source for this claim, sorry) will not pad at all.
C and C++ are different languages but it has always been the C++'s intention that you can have an implementation that supports both languages in a binary compatible fashion. Because they are different languages it is always a compiler implementation detail whether this is actually supported. Typically vendors who supply both a C and C++ compiler (or a single compiler with two modes) do support full compatibility for passing POD-structs (and pointers to POD-structs) between C++ code and C code.
Often, merely having a user-defined constructor breaks the guarantee although sometimes you can pass a pointer to such an object to a C function expecting a pointer to a struct with and identical data structure and it will work.
In short: check your compiler documentation.
Use the same "struct" in both C and C++. If you want to add methods in the C++ implementation, you can inherit the struct and the size should be the same as long as you don't add data members or virtual functions.
Be aware that if you have an empty struct or data members that are empty structs, they are different sizes in C and C++. In C, sizeof(empty-struct) == 0 although in C99, empty-structs are not supposed to be allowed (but may be supported anyway as a "compiler extension"). In C++, sizeof(empty-struct) != 0 (typical value is 1).
In addition to other answers, I would be sure not to put any access specifiers (public:, private: etc) into your C++ class / struct. IIRC the compiler is allowed to reorder blocks of member variables according to visibility, so that private: int a; pubic: int b; might get a and b swapped round. See eg this link: http://www.embedded.com/design/218600150?printable=true
I admit to being baffled as to why the definition of POD does not include a prohibition to this effect.
As long as your class doesn't exhibit some advanced traits of its kind, like growing something virtual, it should be pretty much the same struct.
Besides, you can change Class (which is invalid due to capitalization, anyway) to struct without doing any harm. Except for the members will turn public (they are private now).
But now that I think of your talking about type conversion… There's no way you can turn float into long representing the same value or vice versa by casting pointer type. I hope you only want it these pointers for the sake of moving stuff around.