genode/repos/base/include/util/construct_at.h
Norman Feske a06fd84b75 util/construct_at.h: ensure legit sizeof(Placeable)
If the memory for the designated object is allocated as char[sizeof(T)],
the size of 'Placeable' is expected to equal the size of T. However, in
principle, the compiler has the freedom to inflate the 'Placeable'
object. The static assertion gives us the assurance that the compiler
does not violate our assumption.
2025-01-30 16:30:13 +01:00

88 lines
2.8 KiB
C++

/*
* \brief Utility for the manual placement of objects
* \author Norman Feske
* \date 2014-02-07
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__UTIL__CONSTRUCT_AT_H_
#define _INCLUDE__UTIL__CONSTRUCT_AT_H_
#include <base/stdint.h>
#include <base/log.h>
namespace Genode {
template <typename T, typename... ARGS>
static inline T *construct_at(void *, ARGS &&...);
}
/**
* Construct object of given type at a specific location
*
* \param T object type
* \param at desired object location
* \param args list of arguments for the object constructor
*
* \return typed object pointer
*
* We use move semantics (ARGS &&) because otherwise the compiler would create
* a temporary copy of all arguments that have a reference type and use a
* reference to this copy instead of the original within this function.
*
* There is a slight difference between the object that is constructed by this
* function and a common object of the given type. If the destructor of the
* given type or of any base of the given type is virtual, the vtable of the
* returned object references an empty delete(void *) operator for that
* destructor. However, this shouldn't be a problem as an object constructed by
* this function should never get destructed implicitely or through a delete
* expression.
*/
template <typename T, typename... ARGS>
static inline T * Genode::construct_at(void *at, ARGS &&... args)
{
/**
* Utility to equip an existing type 'T' with a placement new operator
*/
struct Placeable : T
{
Placeable(ARGS &&... args) : T(args...) { }
void * operator new (__SIZE_TYPE__, void *ptr) { return ptr; }
void operator delete (void *, void *) { }
/**
* Standard delete operator
*
* As we explicitely define one version of the delete operator, the
* compiler won't implicitely define any delete version for this class.
* But if type T has a virtual destructor, the compiler implicitely
* defines a 'virtual ~Placeable()' which needs the following operator.
*/
void operator delete (void *)
{
error("cxx: Placeable::operator delete (void *) not supported.");
}
};
static_assert(sizeof(Placeable) == sizeof(T));
/*
* If the args input to this function contains rvalues, the compiler would
* use the according rvalue references as lvalues at the following call if
* we don't cast them back to rvalue references explicitely. We can not use
* lvalues here because the compiler can not bind them to rvalue references
* as expected by Placeable.
*/
return new (at) Placeable(static_cast<ARGS &&>(args)...);
}
#endif /* _INCLUDE__UTIL__CONSTRUCT_AT_H_ */