Note that there are some explanatory texts on larger screens.

plurals
  1. POWhat is the Performance, Safety, and Alignment of a Data member hidden in an embedded char array in a C++ Class?
    text
    copied!<p>I have seen a codebase recently that I fear is violating alignment constraints. I've scrubbed it to produce a minimal example, given below. Briefly, the players are:</p> <ul> <li><p><em>Pool</em>. This is a class which allocates memory efficiently, for some definition of 'efficient'. <em>Pool</em> is guaranteed to return a chunk of memory that is aligned for the requested size.</p></li> <li><p><em>Obj_list</em>. This class stores homogeneous collections of objects. Once the number of objects exceeds a certain threshold, it changes its internal representation from a list to a tree. The size of <em>Obj_list</em> is one pointer (8 bytes on a 64-bit platform). Its populated store will of course exceed that.</p></li> <li><p><em>Aggregate</em>. This class represents a very common object in the system. Its history goes back to the early 32-bit workstation era, and it was 'optimized' (in that same 32-bit era) to use as little space as possible as a result. <em>Aggregate</em>s can be empty, or manage an arbitrary number of objects.</p></li> </ul> <p>In this example, <em>Aggregate</em> items are always allocated from <em>Pool</em>s, so they are always aligned. The only occurrences of <em>Obj_list</em> in this example are the 'hidden' members in <em>Aggregate</em> objects, and therefore they are always allocated using <em>placement new</em>. Here are the support classes:</p> <pre><code>class Pool { public: Pool(); virtual ~Pool(); void *allocate(size_t size); static Pool *default_pool(); // returns a global pool }; class Obj_list { public: inline void *operator new(size_t s, void * p) { return p; } Obj_list(const Args *args); // when constructed, Obj_list will allocate representation_p, which // can take up much more space. ~Obj_list(); private: Obj_list_store *representation_p; }; </code></pre> <p>And here is Aggregate. Note that member declaration <em>member_list_store_d</em>:</p> <pre><code>// Aggregate is derived from Lesser, which is twelve bytes in size class Aggregate : public Lesser { public: inline void *operator new(size_t s) { return Pool::default_pool-&gt;allocate(s); } inline void *operator new(size_t s, Pool *h) { return h-&gt;allocate(s); } public: Aggregate(const Args *args = NULL); virtual ~Aggregate() {}; inline const Obj_list *member_list_store_p() const; protected: char member_list_store_d[sizeof(Obj_list)]; }; </code></pre> <p>It is that data member that I'm most concerned about. Here is the pseudocode for initialization and access:</p> <pre><code>Aggregate::Aggregate(const Args *args) { if (args) { new (static_cast&lt;void *&gt;(member_list_store_d)) Obj_list(args); } else { zero_out(member_list_store_d); } } inline const Obj_list *Aggregate::member_list_store_p() const { return initialized(member_list_store_d) ? (Obj_list *) &amp;member_list_store_d : 0; } </code></pre> <p>You may be tempted to suggest that we replace the char array with a pointer to the <em>Obj_list</em> type, initialized to NULL or an instance of the class. This gives the proper semantics, but just shifts the memory cost around. If memory were still at a premium (and it might be, this is an EDA database representation), replacing the char array with a pointer to an <em>Obj_list</em> would cost one more pointer in the case when <em>Aggregate</em> objects <em>do</em> have members.</p> <p>Besides that, I don't really want to get distracted from the main question here, which is alignment. I <em>think</em> the above construct is problematic, but can't really find more in the standard than some vague discussion of the alignment behavior of the 'system/library' <em>new</em>.</p> <p>So, does the above construct do anything more than cause an occasional pipe stall?</p> <p><strong>Edit</strong>: I realize that there are ways to <em>replace</em> the approach using the embedded char array. So did the original architects. They discarded them because memory was at a premium. Now, if I have a reason to touch that code, I'll probably change it.</p> <p>However, my question, about the alignment issues inherent in this approach, is what I hope people will address. Thanks!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload