144 lines
2.8 KiB
C++
144 lines
2.8 KiB
C++
/**
|
|
* stack_ptr.h
|
|
*
|
|
* Implementation of an object that behaves like a
|
|
* smart pointer but is actually managed on the stack
|
|
*
|
|
* @copyright 2016 Copernica B.V.
|
|
*/
|
|
|
|
/**
|
|
* Dependencies
|
|
*/
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
/**
|
|
* Set up namespace
|
|
*/
|
|
namespace AMQP {
|
|
|
|
/**
|
|
* Stack-based smart pointer
|
|
*/
|
|
template <typename T>
|
|
class stack_ptr
|
|
{
|
|
private:
|
|
/**
|
|
* Storage for the object
|
|
* @var std::aligned_storage<sizeof(T), alignof(T)>
|
|
*/
|
|
std::aligned_storage<sizeof(T), alignof(T)> _data;
|
|
|
|
/**
|
|
* Is the pointer initialized?
|
|
* @var boolean
|
|
*/
|
|
bool _initialized = false;
|
|
public:
|
|
/**
|
|
* Constructor
|
|
*/
|
|
stack_ptr() = default;
|
|
|
|
/**
|
|
* Copy and moving is disabled
|
|
*
|
|
* @param that The stack_ptr we refuse to copy/move
|
|
*/
|
|
stack_ptr(const stack_ptr &that) = delete;
|
|
stack_ptr(stack_ptr &&that) = delete;
|
|
|
|
/**
|
|
* Destructor
|
|
*/
|
|
~stack_ptr()
|
|
{
|
|
// reset the pointer
|
|
reset();
|
|
}
|
|
|
|
/**
|
|
* Reset the pointer
|
|
*/
|
|
void reset()
|
|
{
|
|
// are we initialized?
|
|
if (!_initialized) return;
|
|
|
|
// destroy the object
|
|
reinterpret_cast<T*>(&_data)->~T();
|
|
|
|
// the object is not currently initialized
|
|
_initialized = false;
|
|
}
|
|
|
|
/**
|
|
* Construct the object
|
|
*
|
|
* @param ... Zero or more constructor arguments for T
|
|
*/
|
|
template <typename... Arguments>
|
|
void construct(Arguments&&... parameters)
|
|
{
|
|
// first reset the current object
|
|
reset();
|
|
|
|
// initialize new object
|
|
new (&_data) T(std::forward<Arguments>(parameters)...);
|
|
}
|
|
|
|
/**
|
|
* Is the object initialized?
|
|
*
|
|
* @return Are we currently managing an object?
|
|
*/
|
|
operator bool() const
|
|
{
|
|
// are we initialized with an object?
|
|
return _initialized;
|
|
}
|
|
|
|
/**
|
|
* Retrieve a pointer to the object
|
|
*
|
|
* @return Pointer to the object or nullptr if no object is managed
|
|
*/
|
|
T *get() const
|
|
{
|
|
// do we have a managed object
|
|
if (!_initialized) return nullptr;
|
|
|
|
// return pointer to the managed object
|
|
return const_cast<T*>(reinterpret_cast<const T*>(&_data));
|
|
}
|
|
|
|
/**
|
|
* Retrieve a reference to the object
|
|
*
|
|
* @return Reference to the object, undefined if no object is managed
|
|
*/
|
|
T &operator*() const
|
|
{
|
|
// dereference the pointer
|
|
return *operator->();
|
|
}
|
|
|
|
/**
|
|
* Retrieve a pointer to the object
|
|
*
|
|
* @return Pointer to the object, undefined if no object is managed
|
|
*/
|
|
T *operator->() const
|
|
{
|
|
// return pointer to the managed object
|
|
return const_cast<T*>(reinterpret_cast<const T*>(&_data));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* End namespace
|
|
*/
|
|
}
|