Martin Sebor <mse...@gmail.com> writes: > I do have one concern: the tendency to prioritize efficiency > over safety (this can be said about most GCC code). Specifically > in this class, the address bit twiddling makes me uneasy. I don't > think the object model in either language (certainly not C but > I don't have the impression C++ either) makes it unequivocally > valid. On the contrary, I'd say many of us interpret the current > rules as leaving it undefined. There are efforts to sanction > this sort of thing under some conditions (e.g, the C object > model proposal) but they have not been adopted yet. I think > we should try to avoid exploiting these dark corners in new > code.
I'd tried to stick to operations that I thought were well-defined. The primitives being used are really: (1) convert a T1* or T2* to char* (2) increment an unincremented char* (3) decrement an incremented char* (4) convert a char* back to T1* or T2* (5) convert a char* to an intptr_t in order to test its low bit I thought (1) and (4) were allowed. At least, [basic.compound] says that void* must be able to hold any object pointer and that it must have the same representation as char*, so I thought the conversion in (1) was guaranteed to be representable. And (4) only ever undoes (1): it only converts the result of (1) back to the original pointer type. For (2) and (3), the incremented pointer will still be within the containing object, so I thought it would be well-defined. Here too, (3) only ever undoes (2): it only decrements a pointer that had previously been incremented. One thing I'd deliberately tried to avoid was converting integers “back” to pointers, because that seemed like a more dangerous thing. That's why: >> +template<typename T1, typename T2> >> +inline T2 * >> +pointer_mux<T1, T2>::second_or_null () const >> +{ >> + // Micro optimization that's effective as of GCC 11: compute the value >> + // of the second pointer as an integer and test that, so that the integer >> + // result can be reused as the pointer and so that all computation can >> + // happen before a branch on null. This reduces the number of branches >> + // needed for loops. >> + return uintptr_t (m_ptr - 1) & 1 ? nullptr : known_second (); >> +} is written in a somewhat indirect way. Are your concerns with the primitives above, or is the problem with something else? Thanks, Richard