3

Let's say that a class is completely defined in its .cpp file, so that in the source file you can find:

  • The constructor defined
  • The desctructor defined
  • Every method defined

Than why its private member variables must still be in the header file? Why do we still need PIMPL to get rid of them?

If for this class I also define its own new operator in the source file, why I still need to know the size from the outside code?

Is it because the class can be still stack allocated? If so, than why the "function" who allocates on the stack is not part of the constructor call inside the .cpp file?

nyarlathotep108
  • 5,275
  • 2
  • 26
  • 64
  • 1
    How would you create an object from a set of bits if you didn't know how many bits were needed, and had no way of finding out? – Peter Nov 06 '15 at 10:33
  • Just as a side remark: You dont always need to know the size of an object. E.g. whenever you use a forward declaration, the size is still unknown but still you can use objects of the class. – 463035818_is_not_an_ai Nov 06 '15 at 10:36
  • @Peter using a linked function defined in some other source file which just returns to me a pointer – nyarlathotep108 Nov 06 '15 at 10:57
  • That is insufficient, nyarlathotep. To return a pointer to an object, that "linked function" would also need to create an object from a set of bits. – Peter Nov 06 '15 at 12:38
  • tobi - a forward declaration allows only creation of pointers and references. It is insufficient to use the objects pointed to (if any) or referenced. For example, `some_pointer->some_member_function()` will generate a compilation error unless the actual type definition (not just a forward declaration) is visble to the compiler. – Peter Nov 06 '15 at 12:43

1 Answers1

2

Than why its private member variables must still be in the header file? Why do we still need PIMPL to get rid of them?

Because for many operations - those allowed after a definition's been seen - the compiler needs to know the size of object instances. Further details below.

If for this class I also define its own new operator in the source file, why I still need to know the size from the outside code?

Is it because the class can be still stack allocated? If so, than why the "function" who allocates on the stack is not part of the constructor call inside the .cpp file?

Partly. It's simplest and most efficient for the compiler to move the stack pointer by the total size of local variables as a function call starts, then move it back as it returns. That size can normally be calculated at compile time. If you had runtime functions returning the individual object sizes, then the compiler would need to handle the stack pointer deltas in dribs and drabs, and either repeatedly calculate the address of specific objects at runtime as the cumulative total of earlier allocations, or use memory/registers to maintain a set of pointers or offsets to wherever they end up. (This is one of the main reasons most C++ compilers don't support runtime specification of array dimensions.)

I say "partly" because it's not just about the stack: similar issues apply to static / global and thread-local objects.

Community
  • 1
  • 1
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • I see... basically is it just about performances versus information hiding (so if I really want to hide the private member variables I have to manually do it using PIMPL idiom and heap allocation)? – nyarlathotep108 Nov 06 '15 at 11:01
  • 1
    Another reason is inheritance. If `B` inherits from `A`, thane `B` has to know how much space it has to reserve for inherited `A`. – el.pescado - нет войне Nov 06 '15 at 11:16
  • @nyarlathotep108: that's about the size of it, yes. There are alternatives - such as managing your own static object pools somewhere instead of using the heap - but they don't scale arbitrarily, are wasteful, and/or get more complex than they're usually worth. Or occasionally you see someone reserve "opaque" space in the object a la `private: double impl_[20];` and they do some hacky casting or placement new to create whatever they actually want in that memory, along with static asserts to ensure `impl_` is big enough. (`double` ensures 8 byte alignment, if you're wondering why not `char`). – Tony Delroy Nov 06 '15 at 11:47
  • @nyarlathotep108: and just in case your instinct is "`double impl_[];`? oooh yeah!", let me say don't try it unless you understand "aliasing" and the associated risks of undefined behaviour. – Tony Delroy Nov 06 '15 at 11:49
  • @el.pescado: excellent point...! Lots of subtle issues around that, e.g. friends wanting pointers to private bases that they wouldn't know existed if private details weren't required in the definition. – Tony Delroy Nov 06 '15 at 11:54