diff --git a/base/include/util/construct_at.h b/base/include/util/construct_at.h
new file mode 100644
index 0000000000..57e83d2b42
--- /dev/null
+++ b/base/include/util/construct_at.h
@@ -0,0 +1,84 @@
+/*
+ * \brief Utility for the manual placement of objects
+ * \author Norman Feske
+ * \date 2014-02-07
+ */
+
+/*
+ * Copyright (C) 2014 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#ifndef _INCLUDE__UTIL__CONSTRUCT_AT_H_
+#define _INCLUDE__UTIL__CONSTRUCT_AT_H_
+
+#include
+#include
+
+namespace Genode {
+ template
+ 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
+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_t, 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 *)
+ {
+ PERR("cxx: Placeable::operator delete (void *) not supported.");
+ }
+ };
+
+ /*
+ * 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)...);
+}
+
+#endif /* _INCLUDE__UTIL__CONSTRUCT_AT_H_ */
diff --git a/os/include/util/volatile_object.h b/os/include/util/volatile_object.h
index f80ae84a5b..50213380bb 100644
--- a/os/include/util/volatile_object.h
+++ b/os/include/util/volatile_object.h
@@ -14,6 +14,7 @@
#ifndef _INCLUDE__UTIL__VOLATILE_OBJECT_H_
#define _INCLUDE__UTIL__VOLATILE_OBJECT_H_
+#include
#include
#include
@@ -39,21 +40,6 @@ class Genode::Volatile_object
{
private:
- /**
- * Utility to equip an existing type 'T' with a placement new operator
- */
- template
- struct Placeable : T
- {
- template
- Placeable(ARGS &&... args)
- :
- T(args...)
- { }
-
- void *operator new (size_t, void *ptr) { return ptr; }
- };
-
/**
* Static reservation of memory for the embedded object
*/
@@ -66,7 +52,7 @@ class Genode::Volatile_object
template void _do_construct(ARGS &&... args)
{
- new (_space) Placeable(args...);
+ construct_at(_space, args...);
_constructed = true;
}
diff --git a/os/run/volatile_object.run b/os/run/volatile_object.run
index 8bec6c38c5..c5e06aa712 100644
--- a/os/run/volatile_object.run
+++ b/os/run/volatile_object.run
@@ -59,6 +59,11 @@ compare_output_to {
[init -> test-volatile_object] destruct Member_with_reference
[init -> test-volatile_object] destruct Object 2
[init -> test-volatile_object] destruct Object 1
+[init -> test-volatile_object] -- construct Throwing object
+[init -> test-volatile_object] construct Throwing -> don't throw
+[init -> test-volatile_object] destruct Throwing
+[init -> test-volatile_object] construct Throwing -> throw exception
+[init -> test-volatile_object] -- catched exception as expected
[init -> test-volatile_object] --- test-volatile_object finished ---
}
diff --git a/os/src/test/volatile_object/main.cc b/os/src/test/volatile_object/main.cc
index 72a7119398..3e658bdc68 100644
--- a/os/src/test/volatile_object/main.cc
+++ b/os/src/test/volatile_object/main.cc
@@ -75,6 +75,35 @@ struct Compound
};
+struct Bool
+{
+ bool b;
+
+ Bool(Bool const &) = delete;
+
+ Bool(bool const &b) : b(b) { }
+};
+
+
+struct Throwing
+{
+ Throwing(Bool const &throws)
+ {
+ if (throws.b) {
+ PLOG("construct Throwing -> throw exception");
+ throw -1;
+ } else {
+ PLOG("construct Throwing -> don't throw");
+ }
+ }
+
+ virtual ~Throwing()
+ {
+ PLOG("destruct Throwing");
+ }
+};
+
+
static void call_const_method(Compound const &compound)
{
compound.member->reference.const_method();
@@ -125,6 +154,17 @@ int main(int, char **)
printf("-- destruct Compound and Objects 1 and 2 --\n");
}
+ try {
+ printf("-- construct Throwing object\n");
+ Bool const b_false(false), b_true(true);
+
+ Volatile_object inst(b_false);
+ inst.construct(b_true);
+ PERR("expected contructor to throw");
+ } catch (int i) {
+ printf("-- catched exception as expected\n");
+ }
+
printf("--- test-volatile_object finished ---\n");
return 0;