6

Consider the following code:

aligned_storage<sizeof(T)> buffer;
T& ref(*reinterpret_cast<T*>(&buffer));
new (&buffer) T();
Use(ref);

The context for this is refactoring some global objects into ones which are explicitly initialized (as opposed to initialized by the compiler during static initialization), without affecting existing users (and without using macros).

I think that code causes undefined behaviour as written, but is there any valid (portable) way of accomplishing the same thing? The closest thing I can think of is to use some type with operator T&, but that could still break users.

Bwmat
  • 4,314
  • 3
  • 27
  • 42
  • 2
    `new (&buffer) T();`?? Without assignment? It's pretty unclear what you're asking about at all. – πάντα ῥεῖ Dec 15 '18 at 23:44
  • Yes, without assignment, the object would be accessed via the existing reference rather than the pointer returned by new – Bwmat Dec 15 '18 at 23:49
  • Whoops, fixed a typo, that should make more sense – Bwmat Dec 15 '18 at 23:50
  • I have no clue what you want. Maybe something like _placement new_. – πάντα ῥεῖ Dec 15 '18 at 23:50
  • 1
    That code is doing placement new... – Bwmat Dec 15 '18 at 23:51
  • to be able to explicitly initialise a global var (e.g. Singleton) (e.g. to control order of initialisation of global vars) you can hold them as `unique_ptr`s – Andriy Tylychko Dec 15 '18 at 23:53
  • 1
    I think you should look at [`std::launder`](https://en.cppreference.com/w/cpp/utility/launder) –  Dec 15 '18 at 23:53
  • I've seen launder, but I'm targeting C++03, and my understanding of it is that you can only use it within the lifetime of the object – Bwmat Dec 15 '18 at 23:55
  • @AndriyTylychko I want to maintain the type associated with the identifier for this refactoring, so that isn't an option. – Bwmat Dec 16 '18 at 00:00
  • @Bwmat: my condolences – Andriy Tylychko Dec 16 '18 at 00:02
  • how are you going to detect access before initialisation? – Andriy Tylychko Dec 16 '18 at 00:03
  • 1
    Quote from standard: "A reference shall be initialized to refer to a valid object or function.". The funny thing is, I cannot find the definition of "valid object". It is likely that there is no clear answer for this question. I would not worry about this, if it works with your compiler (very likely). – geza Dec 16 '18 at 00:15
  • @AndriyTylychko Static Initialization Fiasco means it's not really getting worse, lol – Bwmat Dec 16 '18 at 00:25
  • @geza Yeah, that quote seems to prohibit it to me... And I want it to be portable, we use multiple compilers (MSVC, GCC, Clang, Solaris/AIX/HP-UX 'native' compiliers) – Bwmat Dec 16 '18 at 00:27
  • @Bwmat: that's true, but I had an impression you're trying to fix Static Initialization Fiasco? – Andriy Tylychko Dec 16 '18 at 00:33
  • For me, it doesn't mean that. There is a note afterwards, which talks about null pointers. So, in a sense, your reference is "valid". And, pre-C++17, if a `T *` pointer points to an address, where a T object resides, then it points the the object (it doesn't matter, how you got the pointer). If `ref` was a pointer, then your code would not have UB, as far as I understand. If references have the same semantic as pointers in this regard (I don't find anything about this, tough), then your code doesn't have UB. – geza Dec 16 '18 at 00:35
  • I don't think it matters when you get the reference. The `reinterpret_cast` doesn't actually give you a `T*` as per https://stackoverflow.com/a/48164192/5096416 and so dereferencing gives you a strict aliasing error – Lawrence Dec 17 '18 at 16:56

0 Answers0