9

Consider the case in which I've enough storage to host a void * and therefore to construct in-place a pointer.
Is there any guarantee that the same storage is big enough to always store also an std::reference_wrapper?

Kind of (written out of my mind, just to give a grasp of what I mean):

std::aligned_storage_t<sizeof(void *), alignof(void *)> storage;
// ...
int value = 0;
new (&storage) std::reference_wrapper<int>{value};

From a quick and dirty test, I see that on my machine this is valid, that is the size of an std::reference_wrapper fits with that of a void *. However it could be the case on different platforms. At the same time, I cannot find any clue in the standard about the size of and std::reference_wrapper and I'm wondering if it's implementation defined or there are any guarantees.


To give a context, I'm working on an opaque wrapper around different types (similar to std::any) that performs a small object optimization to avoid allocations when possible.
When I receive an std::reference_wrapper, I want to use a different path than that used to differentiate sizeof(T) > sizeof(void *) from the other case around. However, I don't know if I can just copy construct in-place the wrapper or if I should rely on allocations also in this case instead.

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • 2
    FWIW C++ doesn't even specify that a `void*` is the same size as all other pointers. For instance a member function pointer can be larger than `void*`: http://coliru.stacked-crooked.com/a/0cde0ef2f3d7dc3a – NathanOliver Jul 23 '19 at 13:36
  • @NathanOliver indeed, but it says that you can assign a pointer to object to a `void *` while you cannot do the same with pointers to members. I wonder if it says also something like - _a wrapper cannot be larger than a pointer to the same object_. I don't think so but asking looks like a good strategy before to proceed. :-) – skypjack Jul 23 '19 at 13:38
  • Datapoint: gcc's [current implementation](https://github.com/gcc-mirror/gcc/blob/41d6b10e96a1de98e90a7c0378437c3255814b16/libstdc%2B%2B-v3/include/bits/refwrap.h) has `sizeof(std::reference_wrapper) == sizeof(T*)` (although I agree with NathanOliver that this is not guaranteed) – AndyG Jul 23 '19 at 14:01
  • Another datapoint: clang's [current implementation](https://github.com/llvm-mirror/libcxx/blob/56bc01df8f4f30fe28f94f20b13c3e8e76c0cf71/include/__functional_base) also has `sizeof(std::reference_wrapper) == sizeof(T*)` – AndyG Jul 23 '19 at 14:15

2 Answers2

7

The C++ standard does not pose any size requirements. Per [refwrap]

  1. reference_­wrapper<T> is a Cpp17CopyConstructible and Cpp17CopyAssignable wrapper around a reference to an object or function of type T.
  2. reference_­wrapper<T> is a trivially copyable type.

All we know is that is copyable, and it is trivial. Other than that it it left up to the implementation. Typically it is just a wrapper for a T*, but the implementation might have some other members in there for some reason

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
7

There is no guarantee in the standard.

No sensible implementation is going to use more than a pointer.

static_assert it fits and you have enough alignment so your code is correct (and people can see it is correct). That static assert won't ever be hit.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524