3

I have database project that I want to move from C to C++. In this C project I have lots of small packed structs, that I write directly to file or read from mmaped file - e.g. directly from memory address.

I need the class in-memory representation, to be exactlybthe same as if I use plain old C struct. I believe this is called POD or C++ standard layout.

I can proceed in several ways:

I can do class, bu I worry that if I add methods to this struct, probably the internal structure will be changed.

If I wrap the a structure into class, I will need to create / destroy classes all the time, along with the structs.

If I do it C - OO style, I will need to supply pointer to every function, e.g.

static const char *Pair::getKey(const void *mem);

I can also make the struct a field and do something similar

void Pair::setMem(const void *mem);
const char *Pair::getKey();

but the more I see this, the less I like it, because there is no real advantage.

Anything I am missing?

Nick
  • 9,962
  • 4
  • 42
  • 80
  • 2
    "If I add methods to this struct, probably the internal structure will be changed" - no, only if you add **variables**. Methods do not affect the size of structures and classes, except for when you add the **first** virtual function, which makes the compiler add a pointer to the V-Table (so each instance grows by `sizeof(void*)`). – barak manos Jun 20 '15 at 16:59
  • can i add normal methods - non static non virtual methods? Is it work for static methods too? Is this guaranteed? Can I do Pair *p = (Pair *)some_addr; e.g without new Pair – Nick Jun 20 '15 at 17:05
  • Why don't you simply try and find out??? – barak manos Jun 20 '15 at 17:14
  • because if it works with my compiller does not make it correct way – Nick Jun 20 '15 at 17:23
  • Well, why don't you share your way (i.e. some **actual code**) with us, so someone here can refer to it directly and correct you where necessary? – barak manos Jun 20 '15 at 17:25
  • I do not have C++ code to share yet. – Nick Jun 20 '15 at 17:32
  • possible duplicate of [What are the differences between struct and class in C++?](http://stackoverflow.com/questions/92859/what-are-the-differences-between-struct-and-class-in-c) – kfsone Jun 21 '15 at 01:30
  • You really should consider learning more about C++ before you decide to "move" a project. I've worked with a lot of code bases, and the worst have been people who decided to "switch" to C++ from C. – kfsone Jun 21 '15 at 01:39
  • Sure, I lack terminology. If I knew I want so called POD I would say it at the beginning. And sure I will left most of project in C way, except in places where C++ differs. – Nick Jun 21 '15 at 07:45

3 Answers3

5

If I add methods to this struct, probably the internal structure will be changed.

That's wrong; to satisfy your needs what you want is to keep your structure a POD, for which essentially you don't want:

  • non-trivial constructors/destructors/assignment operators;
  • virtual functions or virtual base classes;
  • different access specifiers for data members.

(there are some additional restrictions (see C++11 §9 ¶6-10), but they are not particularly relevant in your case)

The "POD" thing implies two things:

  • that your class is "standard layout", which roughly means "laid out in a well-defined manner, the same way as C would do" (which assesses your primary concern);

    adding methods shouldn't break stuff, since, as they aren't be virtual, they are translated as free functions which take a pointer to the object as hidden parameter, and that requires no modification to the original C layout. static methods are just free functions with different scoping, so in general they are a non-issue.

  • that your class can be freely copyable with a memcpy without stuff breaking, which is probably what you want if you read it straight from file (either with mmap or with fread);

    this is accounted for by the "triviality" of the constructors (i.e. if they are skipped nothing bad happens to your objects) and by the absence of virtual members, which means that you don't risk overwriting the vptr with a stale one read from the file.

Community
  • 1
  • 1
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • POD is not a technical term in C++11, your post conflates standard layout and trivial. It's not really clear from the initial post that trivial is something that he needs or not. Also, it is only data members (and none static ones at that) which must have the same access specifier, this makes a huge difference as one can just make all the data private anyhow. – Nir Friedman Jun 20 '15 at 17:11
  • 1
    @NirFriedman: POD *is* a technical term defined at §9 ¶10, and essentially it means that (1) it's C-compatible with a well-defined layout (standard layout) and (2) it's trivially copyable, so you can `memcpy` it freely without breaking stuff, which is what you want if you are sharing an object between two processes (the virtual memory will make the actual `memcpy` disappear, but it's as if it was there). As for the access specifier of the data members, my bad, I'll fix it. – Matteo Italia Jun 20 '15 at 17:16
  • Sorry, you're correct about POD being both. He does not say that he wants to share between two processes, just that he needs to be able to read and write directly from memory. Constructing the object in C++ may involve some additional steps to make it ready to use in C++, but have nothing to do with its in memory representation (e.g. increment a static integer to count how many classes exist). In short it seems like an assumption that the user requires triviality. – Nir Friedman Jun 20 '15 at 17:23
3

C++11 has a specific concept called standard layout, it basically means that for classes meeting the standard layout requirements, it guarantees that the class will be laid out in memory identically to C. The requirements are:

  • All non-static data members have the same access control
  • Has no virtual functions or virtual base classes
  • All non-static data members and base classes are themselves standard layout types
  • Has no two base class subobjects of the same type

So you can add methods to your classes, as long as you're careful. See http://en.cppreference.com/w/cpp/concept/StandardLayoutType.

Nir Friedman
  • 17,108
  • 2
  • 44
  • 72
1

If I add methods to this struct, probably the internal structure will be changed.

This is unlikely, at least no more so than changing compiler (from C to C++). You can add methods, as long as they aren't constructors, destructors, assignment operators, or virtual functions, and the memory layout is guaranteed to not change.

For more information, see Structure of a C++ Object in Memory Vs a Struct

If I wrap the structure into class, I will need to create / destroy classes all the time.

Which is exactly the same as creating and destroying structs all the time. Class instantiation in C++ consists of a memory allocation and a call to a constructor. You have the same control over the allocation as you do with a struct, and you control all of the code in the constructor (including the option to have no code at all).

It is perfectly legal to write C code and build it using a C++ compiler. It is also possible to write C++ code (under a few restrictions) that compiles to exactly the same binary as that C code. What using class/struct members gets you is a (arguably) cleaner syntax and implied currying of the this pointer. For example:

// C
ret = CallMyStructMethodX(pMyStruct, param1, param2);

// C++
ret = pMyStruct->CallMethodX(param1, param2);

These two lines of code will are identical. The only difference is that in the latter case, your struct pointer is passed by the implied this parameter, rather than as an explicit parameter to the function.

Ryan Bemrose
  • 9,018
  • 1
  • 41
  • 54
  • What is more expencive new or malloc? – Nick Jun 20 '15 at 23:00
  • 2
    Like I said, new() is just malloc + ctor, so if your ctor does nothing, they should be exactly the same, and they both generally use whatever passes for a heap alloc. If you're seriously concerned about performance you should be allocating on the stack or pre-allocated memory (Look up "placement new"). As always, never take someone else's word for performance though. Profile, profile, profile. – Ryan Bemrose Jun 21 '15 at 00:02
  • I change constructor to factory method, it uses malloc(), because last class member have variable lenght array, then I am casting the buffer to the class and filling the fields - works great with gcc and clang. Finally, instead of delete, I am using free(). It is bit ugly, but low level works exactly as in C. – Nick Jun 21 '15 at 07:54