Shmoopy Shmoopy - 1 month ago 10
C++ Question

Why is LLVM's Optional<T> implemented this way?

I stumbled upon an implemenation of

Optional<T>
which is based on LLVM's Optional.h class and couldn't quite figure out why it is implemented the way it is.

To keep it short, I'm only pasting the parts I don't understand:

template <typename T>
class Optional
{
private:
inline void* getstg() const { return const_cast<void*>(reinterpret_cast<const void*>(&_stg)); }
typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type storage_type;
storage_type _stg;
bool _hasValue;

public:

Optional(const T &y) : _hasValue(true)
{
new (getstg()) T(y);
}

T* Get() { return reinterpret_cast<T*>(getstg()); }
}


And the most naive implementation I could think of:

template <typename T>
class NaiveOptional
{
private:
T* _value;
bool _hasValue;

public:
NaiveOptional(const T &y) : _hasValue(true), _value(new T(y))
{
}

T* Get() { return _value; }
}


Questions:


  1. How do I interpret the
    storage_type
    ? what was the author's intention?

  2. What is the semantics of this line:
    new (getstg()) T(y);
    ?

  3. Why doesn't the naive implementation work (or, what pros does the
    Optional<T>
    class have over
    NaiveOptional<T>
    ) ?


dvk dvk
Answer

The short answer is "performance".

Longer answer:

  1. storage_type provides an in-memory region that is (a) big enough to fit the type T and (b) is aligned properly for type T. Unaligned memory access is slower. See also the doc.
  2. new (getstg()) T(y) is a placement new. It does not allocate memory, but instead it constructs an object in memory region passed to it. The doc (on all forms of new - search for the "placement new").
  3. The naive implementation does work, but it has worse performance. It uses dynamic memory allocation, which often can be a bottleneck. The Optional<T> implementation does not use dynamic memory allocation (see the point above).
Comments