Merge branch 'develop' into feature/allocators
diff --git a/Makefile b/Makefile
index 98f0768..46d176c 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@
 FLAGS = -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wfloat-equal
 
 # build unit tests (TODO: Does this want its own makefile?)
-json_unit: test/src/unit.cpp src/json.hpp test/src/catch.hpp
+json_unit: test/src/unit.cpp src/json.hpp test/src/catch.hpp test/src/StlAllocatorMock.hpp test/src/StlAllocatorMockState.hpp
 	$(CXX) -std=c++11 $(CXXFLAGS) $(FLAGS) $(CPPFLAGS) -I src -I test $< $(LDFLAGS) -o $@
 
 
@@ -77,7 +77,9 @@
 	   --indent-col1-comments --pad-oper --pad-header --align-pointer=type \
 	   --align-reference=type --add-brackets --convert-tabs --close-templates \
 	   --lineend=linux --preserve-date --suffix=none --formatted \
-	   src/json.hpp src/json.hpp.re2c test/src/unit.cpp test/src/fuzz.cpp benchmarks/benchmarks.cpp doc/examples/*.cpp
+	   src/json.hpp src/json.hpp.re2c test/src/unit.cpp test/src/fuzz.cpp \
+	   test/src/StlAllocatorMock.hpp test/src/StlAllocatorMockState.hpp \
+	   benchmarks/benchmarks.cpp doc/examples/*.cpp
 
 
 ##########################################################################
diff --git a/README.md b/README.md
index 5849067..ed1e807 100644
--- a/README.md
+++ b/README.md
@@ -505,7 +505,7 @@
 $ ./json_unit "*"
 
 ===============================================================================
-All tests passed (8905012 assertions in 32 test cases)
+All tests passed (5568724 assertions in 33 test cases)
 ```
 
 For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
diff --git a/src/json.hpp b/src/json.hpp
index 9d2305d..d4b6f40 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -269,9 +269,9 @@
     /*!
     @brief returns the allocator associated with the container
     */
-    static allocator_type get_allocator()
+    allocator_type get_allocator() const
     {
-        return allocator_type();
+        return m_allocator;
     }
 
 
@@ -373,6 +373,9 @@
           AllocatorType<std::pair<const StringType,
           basic_json>>>;
 
+    static_assert(std::is_member_function_pointer<decltype(&object_t::get_allocator)>::value,
+                  "object type is not allocator aware");
+
     /*!
     @brief a type for an array
 
@@ -419,6 +422,9 @@
     */
     using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
 
+    static_assert(std::is_member_function_pointer<decltype(&array_t::get_allocator)>::value,
+                  "array type is not allocator aware");
+
     /*!
     @brief a type for a string
 
@@ -466,6 +472,9 @@
     */
     using string_t = StringType;
 
+    static_assert(std::is_member_function_pointer<decltype(&string_t::get_allocator)>::value,
+                  "string type is not allocator aware");
+
     /*!
     @brief a type for a boolean
 
@@ -750,15 +759,17 @@
 
     /// helper for exception-safe object creation
     template<typename T, typename... Args>
-    static T* create(Args&& ... args)
+    static T* create(const allocator_type& allocator, Args&& ... args)
     {
-        AllocatorType<T> alloc;
+        AllocatorType<T> alloc(allocator);
         auto deleter = [&](T * object)
         {
-            alloc.deallocate(object, 1);
+            std::allocator_traits<AllocatorType<T>>::deallocate(alloc, object, 1);
         };
-        std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
-        alloc.construct(object.get(), std::forward<Args>(args)...);
+        std::unique_ptr<T, decltype(deleter)> object(std::allocator_traits<AllocatorType<T>>::allocate(
+                    alloc, 1), deleter);
+        std::allocator_traits<AllocatorType<T>>::construct(alloc, object.get(),
+                                             std::forward<Args>(args)...);
         assert(object.get() != nullptr);
         return object.release();
     }
@@ -819,25 +830,25 @@
         /// constructor for numbers (floating-point)
         json_value(number_float_t v) noexcept : number_float(v) {}
         /// constructor for empty values of a given type
-        json_value(value_t t)
+        json_value(const allocator_type& allocator, value_t t)
         {
             switch (t)
             {
                 case value_t::object:
                 {
-                    object = create<object_t>();
+                    object = create<object_t>(allocator, allocator);
                     break;
                 }
 
                 case value_t::array:
                 {
-                    array = create<array_t>();
+                    array = create<array_t>(allocator, allocator);
                     break;
                 }
 
                 case value_t::string:
                 {
-                    string = create<string_t>("");
+                    string = create<string_t>(allocator, "");
                     break;
                 }
 
@@ -874,20 +885,35 @@
 
         /// constructor for strings
         json_value(const string_t& value)
+            : json_value(value.get_allocator(), value)
+        {}
+
+        /// constructor for strings
+        json_value(const allocator_type& allocator, const string_t& value)
         {
-            string = create<string_t>(value);
+            string = create<string_t>(allocator, value);
         }
 
         /// constructor for objects
         json_value(const object_t& value)
+            : json_value(value.get_allocator(), value)
+        {}
+
+        /// constructor for objects
+        json_value(const allocator_type& allocator, const object_t& value)
         {
-            object = create<object_t>(value);
+            object = create<object_t>(allocator, value, allocator);
         }
 
         /// constructor for arrays
         json_value(const array_t& value)
+            : json_value(value.get_allocator(), value)
+        {}
+
+        /// constructor for arrays
+        json_value(const allocator_type& allocator, const array_t& value)
         {
-            array = create<array_t>(value);
+            array = create<array_t>(allocator, value, allocator);
         }
     };
 
@@ -1005,6 +1031,7 @@
     array       | `[]`
 
     @param[in] value_type  the type of the value to create
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1028,8 +1055,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const value_t value_type)
-        : m_type(value_type), m_value(value_type)
+    basic_json(const value_t value_type,
+               const allocator_type& allocator = {})
+        : m_type(value_type),
+          m_value(allocator, value_type),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1038,6 +1068,8 @@
     Create a `null` JSON value. This is the implicit version of the `null`
     value constructor as it takes no parameters.
 
+    @param[in] allocator  the allocator to use to construct objects (optional)
+
     @complexity Constant.
 
     @exceptionsafety No-throw guarantee: this constructor never throws
@@ -1056,7 +1088,9 @@
 
     @since version 1.0.0
     */
-    basic_json() = default;
+    basic_json(const allocator_type& allocator = {}) noexcept
+        : m_allocator(allocator)
+    {}
 
     /*!
     @brief create a null object (explicitly)
@@ -1067,6 +1101,8 @@
     The passed null pointer itself is not read -- it is only used to choose
     the right constructor.
 
+    @param[in] allocator  the allocator to use to construct objects (optional)
+
     @complexity Constant.
 
     @exceptionsafety No-throw guarantee: this constructor never throws
@@ -1080,8 +1116,9 @@
 
     @since version 1.0.0
     */
-    basic_json(std::nullptr_t) noexcept
-        : basic_json(value_t::null)
+    basic_json(std::nullptr_t,
+               const allocator_type& allocator = {}) noexcept
+        : basic_json(value_t::null, allocator)
     {}
 
     /*!
@@ -1090,6 +1127,7 @@
     Create an object JSON value with a given content.
 
     @param[in] val  a value for the object
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1103,8 +1141,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const object_t& val)
-        : m_type(value_t::object), m_value(val)
+    basic_json(const object_t& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::object),
+          m_value(allocator, val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1121,6 +1162,7 @@
     basic_json value can be constructed.
 
     @param[in] val  a value for the object
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1138,12 +1180,17 @@
                   std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
                   std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
               = 0>
-    basic_json(const CompatibleObjectType& val)
-        : m_type(value_t::object)
+    basic_json(const CompatibleObjectType& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::object),
+          m_allocator(allocator)
     {
         using std::begin;
         using std::end;
-        m_value.object = create<object_t>(begin(val), end(val));
+        m_value.object = create<object_t>(m_allocator,
+                                          begin(val), end(val),
+                                          std::less<StringType>(),
+                                          m_allocator);
     }
 
     /*!
@@ -1152,6 +1199,7 @@
     Create an array JSON value with a given content.
 
     @param[in] val  a value for the array
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1165,8 +1213,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const array_t& val)
-        : m_type(value_t::array), m_value(val)
+    basic_json(const array_t& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::array),
+          m_value(allocator, val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1183,6 +1234,7 @@
     `value_type` from which a @ref basic_json value can be constructed.
 
     @param[in] val  a value for the array
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1205,12 +1257,16 @@
                   not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
                   std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type
               = 0>
-    basic_json(const CompatibleArrayType& val)
-        : m_type(value_t::array)
+    basic_json(const CompatibleArrayType& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::array),
+          m_allocator(allocator)
     {
         using std::begin;
         using std::end;
-        m_value.array = create<array_t>(begin(val), end(val));
+        m_value.array = create<array_t>(m_allocator,
+                                        begin(val), end(val),
+                                        m_allocator);
     }
 
     /*!
@@ -1219,6 +1275,7 @@
     Create an string JSON value with a given content.
 
     @param[in] val  a value for the string
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1234,8 +1291,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const string_t& val)
-        : m_type(value_t::string), m_value(val)
+    basic_json(const string_t& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::string),
+          m_value(allocator, val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1244,6 +1304,7 @@
     Create a string JSON value with a given content.
 
     @param[in] val  a literal value for the string
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1258,8 +1319,9 @@
 
     @since version 1.0.0
     */
-    basic_json(const typename string_t::value_type* val)
-        : basic_json(string_t(val))
+    basic_json(const typename string_t::value_type* val,
+               const allocator_type& allocator = {})
+        : basic_json(string_t(val, allocator), allocator)
     {}
 
     /*!
@@ -1268,6 +1330,7 @@
     Create a string JSON value with a given content.
 
     @param[in] val  a value for the string
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @tparam CompatibleStringType an string type which is compatible to @ref
     string_t, for instance `std::string`.
@@ -1289,8 +1352,9 @@
               std::enable_if<
                   std::is_constructible<string_t, CompatibleStringType>::value, int>::type
               = 0>
-    basic_json(const CompatibleStringType& val)
-        : basic_json(string_t(val))
+    basic_json(const CompatibleStringType& val,
+               const allocator_type& allocator = {})
+        : basic_json(string_t(val, allocator), allocator)
     {}
 
     /*!
@@ -1299,6 +1363,7 @@
     Creates a JSON boolean type from a given value.
 
     @param[in] val  a boolean value to store
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1307,8 +1372,11 @@
 
     @since version 1.0.0
     */
-    basic_json(boolean_t val) noexcept
-        : m_type(value_t::boolean), m_value(val)
+    basic_json(boolean_t val,
+               const allocator_type& allocator = {}) noexcept
+        : m_type(value_t::boolean),
+          m_value(val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1322,6 +1390,7 @@
     the helper type @a T is not visible in this constructor's interface.
 
     @param[in] val  an integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1340,8 +1409,11 @@
                  and std::is_same<T, number_integer_t>::value
                  , int>::type
              = 0>
-    basic_json(const number_integer_t val) noexcept
-        : m_type(value_t::number_integer), m_value(val)
+    basic_json(const number_integer_t val,
+               const allocator_type& allocator = {}) noexcept
+        : m_type(value_t::number_integer),
+          m_value(val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1350,6 +1422,7 @@
     Create an integer number JSON value with a given content.
 
     @param[in] val  an integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @note This constructor allows to pass enums directly to a constructor. As
     C++ has no way of specifying the type of an anonymous enum explicitly, we
@@ -1369,9 +1442,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const int val) noexcept
+    basic_json(const int val,
+               const allocator_type& allocator = {}) noexcept
         : m_type(value_t::number_integer),
-          m_value(static_cast<number_integer_t>(val))
+          m_value(static_cast<number_integer_t>(val)),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1386,6 +1461,7 @@
     `long`, and `short`.
 
     @param[in] val  an integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1406,9 +1482,11 @@
                  std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
                  CompatibleNumberIntegerType>::type
              = 0>
-    basic_json(const CompatibleNumberIntegerType val) noexcept
+    basic_json(const CompatibleNumberIntegerType val,
+               const allocator_type& allocator = {}) noexcept
         : m_type(value_t::number_integer),
-          m_value(static_cast<number_integer_t>(val))
+          m_value(static_cast<number_integer_t>(val)),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1420,6 +1498,7 @@
     visible in) the interface.
 
     @param[in] val  an integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1434,8 +1513,11 @@
                  and std::is_same<T, number_unsigned_t>::value
                  , int>::type
              = 0>
-    basic_json(const number_unsigned_t val) noexcept
-        : m_type(value_t::number_unsigned), m_value(val)
+    basic_json(const number_unsigned_t val,
+               const allocator_type& allocator = {}) noexcept
+        : m_type(value_t::number_unsigned),
+          m_value(val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1450,6 +1532,7 @@
     `uint32_t`, or `unsigned short`.
 
     @param[in] val  an unsigned integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1465,9 +1548,11 @@
                   not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
                   CompatibleNumberUnsignedType>::type
               = 0>
-    basic_json(const CompatibleNumberUnsignedType val) noexcept
+    basic_json(const CompatibleNumberUnsignedType val,
+               const allocator_type& allocator = {}) noexcept
         : m_type(value_t::number_unsigned),
-          m_value(static_cast<number_unsigned_t>(val))
+          m_value(static_cast<number_unsigned_t>(val)),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1476,6 +1561,7 @@
     Create a floating-point number JSON value with a given content.
 
     @param[in] val  a floating-point value to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
     disallows NaN values:
@@ -1494,8 +1580,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const number_float_t val) noexcept
-        : m_type(value_t::number_float), m_value(val)
+    basic_json(const number_float_t val,
+               const allocator_type& allocator = {}) noexcept
+        : m_type(value_t::number_float),
+          m_value(val),
+          m_allocator(allocator)
     {
         // replace infinity and NAN by null
         if (not std::isfinite(val))
@@ -1517,6 +1606,7 @@
     or `double`.
 
     @param[in] val  a floating-point to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
     disallows NaN values:
@@ -1541,8 +1631,9 @@
                  std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
                  std::is_floating_point<CompatibleNumberFloatType>::value>::type
              >
-    basic_json(const CompatibleNumberFloatType val) noexcept
-        : basic_json(number_float_t(val))
+    basic_json(const CompatibleNumberFloatType val,
+               const allocator_type& allocator = {}) noexcept
+        : basic_json(number_float_t(val), allocator)
     {}
 
     /*!
@@ -1597,6 +1688,8 @@
     value_t::array and @ref value_t::object are valid); when @a type_deduction
     is set to `true`, this parameter has no effect
 
+    @param[in] allocator  the allocator to use to construct objects (optional)
+
     @throw std::domain_error if @a type_deduction is `false`, @a manual_type
     is `value_t::object`, but @a init contains an element which is not a pair
     whose first element is a string; example: `"cannot create object from
@@ -1616,7 +1709,9 @@
     */
     basic_json(std::initializer_list<basic_json> init,
                bool type_deduction = true,
-               value_t manual_type = value_t::array)
+               value_t manual_type = value_t::array,
+               const allocator_type& allocator = {})
+        : m_allocator(allocator)
     {
         // check if each element is an array with two elements whose first
         // element is a string
@@ -1646,7 +1741,7 @@
         {
             // the initializer list is a list of pairs -> create object
             m_type = value_t::object;
-            m_value = value_t::object;
+            m_value = json_value(m_allocator, value_t::object);
 
             assert(m_value.object != nullptr);
 
@@ -1659,7 +1754,7 @@
         {
             // the initializer list describes an array -> create array
             m_type = value_t::array;
-            m_value.array = create<array_t>(init);
+            m_value.array = create<array_t>(m_allocator, init, m_allocator);
         }
     }
 
@@ -1682,6 +1777,7 @@
 
     @param[in] init  initializer list with JSON values to create an array from
     (optional)
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @return JSON array value
 
@@ -1698,9 +1794,10 @@
     @since version 1.0.0
     */
     static basic_json array(std::initializer_list<basic_json> init =
-                                std::initializer_list<basic_json>())
+                                std::initializer_list<basic_json>(),
+                            const allocator_type& allocator = {})
     {
-        return basic_json(init, false, value_t::array);
+        return basic_json(init, false, value_t::array, allocator);
     }
 
     /*!
@@ -1718,6 +1815,7 @@
     value_t).
 
     @param[in] init  initializer list to create an object from (optional)
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @return JSON object value
 
@@ -1738,9 +1836,10 @@
     @since version 1.0.0
     */
     static basic_json object(std::initializer_list<basic_json> init =
-                                 std::initializer_list<basic_json>())
+                                 std::initializer_list<basic_json>(),
+                             const allocator_type& allocator = {})
     {
-        return basic_json(init, false, value_t::object);
+        return basic_json(init, false, value_t::object, allocator);
     }
 
     /*!
@@ -1752,6 +1851,7 @@
 
     @param[in] cnt  the number of JSON copies of @a val to create
     @param[in] val  the JSON value to copy
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in @a cnt.
 
@@ -1761,10 +1861,12 @@
 
     @since version 1.0.0
     */
-    basic_json(size_type cnt, const basic_json& val)
-        : m_type(value_t::array)
+    basic_json(size_type cnt, const basic_json& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::array),
+          m_allocator(allocator)
     {
-        m_value.array = create<array_t>(cnt, val);
+        m_value.array = create<array_t>(m_allocator, cnt, val, m_allocator);
     }
 
     /*!
@@ -1784,6 +1886,7 @@
 
     @param[in] first begin of the range to copy from (included)
     @param[in] last end of the range to copy from (excluded)
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @throw std::domain_error if iterators are not compatible; that is, do not
     belong to the same JSON value; example: `"iterators are not compatible"`
@@ -1807,7 +1910,10 @@
                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value
                   , int>::type
               = 0>
-    basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
+    basic_json(InputIT first, InputIT last,
+               const allocator_type& allocator = {})
+        : m_type(first.m_object->m_type),
+          m_allocator(allocator)
     {
         // make sure iterator fits the current value
         if (first.m_object != last.m_object)
@@ -1876,13 +1982,20 @@
 
             case value_t::object:
             {
-                m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
+                m_value.object = create<object_t>(m_allocator,
+                                                  first.m_it.object_iterator,
+                                                  last.m_it.object_iterator,
+                                                  std::less<StringType>(),
+                                                  m_allocator);
                 break;
             }
 
             case value_t::array:
             {
-                m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
+                m_value.array = create<array_t>(m_allocator,
+                                                first.m_it.array_iterator,
+                                                last.m_it.array_iterator,
+                                                m_allocator);
                 break;
             }
 
@@ -1901,6 +2014,7 @@
     @param[in] cb a parser callback function of type @ref parser_callback_t
     which is used to control the deserialization by filtering unwanted values
     (optional)
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the length of the input. The parser is a predictive
     LL(1) parser. The complexity can be higher if the parser callback function
@@ -1914,9 +2028,11 @@
 
     @since version 2.0.0
     */
-    explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr)
+    explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr,
+                        const allocator_type& allocator = {})
+        : m_allocator(allocator)
     {
-        *this = parser(i, cb).parse();
+        *this = parser(i, cb, allocator).parse();
     }
 
     ///////////////////////////////////////
@@ -1946,7 +2062,8 @@
     @since version 1.0.0
     */
     basic_json(const basic_json& other)
-        : m_type(other.m_type)
+        : m_type(other.m_type),
+          m_allocator(other.m_allocator)
     {
         switch (m_type)
         {
@@ -2022,7 +2139,8 @@
     */
     basic_json(basic_json&& other) noexcept
         : m_type(std::move(other.m_type)),
-          m_value(std::move(other.m_value))
+          m_value(std::move(other.m_value)),
+          m_allocator(std::move(other.m_allocator))
     {
         // invalidate payload
         other.m_type = value_t::null;
@@ -2086,25 +2204,25 @@
         {
             case value_t::object:
             {
-                AllocatorType<object_t> alloc;
-                alloc.destroy(m_value.object);
-                alloc.deallocate(m_value.object, 1);
+                AllocatorType<object_t> alloc(m_allocator);
+                std::allocator_traits<AllocatorType<object_t>>::destroy(alloc, m_value.object);
+                std::allocator_traits<AllocatorType<object_t>>::deallocate(alloc, m_value.object, 1);
                 break;
             }
 
             case value_t::array:
             {
-                AllocatorType<array_t> alloc;
-                alloc.destroy(m_value.array);
-                alloc.deallocate(m_value.array, 1);
+                AllocatorType<array_t> alloc(m_allocator);
+                std::allocator_traits<AllocatorType<array_t>>::destroy(alloc, m_value.array);
+                std::allocator_traits<AllocatorType<array_t>>::deallocate(alloc, m_value.array, 1);
                 break;
             }
 
             case value_t::string:
             {
-                AllocatorType<string_t> alloc;
-                alloc.destroy(m_value.string);
-                alloc.deallocate(m_value.string, 1);
+                AllocatorType<string_t> alloc(m_allocator);
+                std::allocator_traits<AllocatorType<string_t>>::destroy(alloc, m_value.string);
+                std::allocator_traits<AllocatorType<string_t>>::deallocate(alloc, m_value.string, 1);
                 break;
             }
 
@@ -2152,7 +2270,10 @@
     */
     string_t dump(const int indent = -1) const
     {
-        std::stringstream ss;
+        std::basic_stringstream<typename string_t::value_type,
+            typename string_t::traits_type,
+            typename string_t::allocator_type> ss;
+
         // fix locale problems
         ss.imbue(std::locale(std::locale(), new DecimalSeparator));
 
@@ -3327,7 +3448,7 @@
         if (is_null())
         {
             m_type = value_t::array;
-            m_value.array = create<array_t>();
+            m_value.array = create<array_t>(m_allocator, m_allocator);
         }
 
         // operator[] only works for arrays
@@ -3416,7 +3537,7 @@
         if (is_null())
         {
             m_type = value_t::object;
-            m_value.object = create<object_t>();
+            m_value.object = create<object_t>(m_allocator, m_allocator);
         }
 
         // operator[] only works for objects
@@ -3575,7 +3696,7 @@
         if (is_null())
         {
             m_type = value_t::object;
-            m_value = value_t::object;
+            m_value = json_value(m_allocator, value_t::object);
         }
 
         // at only works for objects
@@ -4906,7 +5027,7 @@
         if (is_null())
         {
             m_type = value_t::array;
-            m_value = value_t::array;
+            m_value = json_value(m_allocator, value_t::array);
         }
 
         // add element to array (move semantics)
@@ -4942,7 +5063,7 @@
         if (is_null())
         {
             m_type = value_t::array;
-            m_value = value_t::array;
+            m_value = json_value(m_allocator, value_t::array);
         }
 
         // add element to array
@@ -4992,7 +5113,7 @@
         if (is_null())
         {
             m_type = value_t::object;
-            m_value = value_t::object;
+            m_value = json_value(m_allocator, value_t::object);
         }
 
         // add element to array
@@ -5896,6 +6017,7 @@
     @param[in] cb a parser callback function of type @ref parser_callback_t
     which is used to control the deserialization by filtering unwanted values
     (optional)
+    @param[in] allocator the allocator to use to construct objects (optional)
 
     @return result of the deserialization
 
@@ -5914,9 +6036,10 @@
     @since version 1.0.0
     */
     static basic_json parse(const string_t& s,
-                            const parser_callback_t cb = nullptr)
+                            const parser_callback_t cb = nullptr,
+                            const allocator_type& allocator = {})
     {
-        return parser(s, cb).parse();
+        return parser(s, cb, allocator).parse();
     }
 
     /*!
@@ -5926,6 +6049,7 @@
     @param[in] cb a parser callback function of type @ref parser_callback_t
     which is used to control the deserialization by filtering unwanted values
     (optional)
+    @param[in] allocator the allocator to use to construct objects (optional)
 
     @return result of the deserialization
 
@@ -5944,18 +6068,20 @@
     @since version 1.0.0
     */
     static basic_json parse(std::istream& i,
-                            const parser_callback_t cb = nullptr)
+                            const parser_callback_t cb = nullptr,
+                            const allocator_type& allocator = {})
     {
-        return parser(i, cb).parse();
+        return parser(i, cb, allocator).parse();
     }
 
     /*!
     @copydoc parse(std::istream&, const parser_callback_t)
     */
     static basic_json parse(std::istream&& i,
-                            const parser_callback_t cb = nullptr)
+                            const parser_callback_t cb = nullptr,
+                            const allocator_type& allocator = {})
     {
-        return parser(i, cb).parse();
+        return parser(i, cb, allocator).parse();
     }
 
     /*!
@@ -5983,7 +6109,7 @@
     */
     friend std::istream& operator<<(basic_json& j, std::istream& i)
     {
-        j = parser(i).parse();
+        j = parser(i, nullptr, j.get_allocator()).parse();
         return i;
     }
 
@@ -5993,7 +6119,7 @@
     */
     friend std::istream& operator>>(std::istream& i, basic_json& j)
     {
-        j = parser(i).parse();
+        j = parser(i, nullptr, j.get_allocator()).parse();
         return i;
     }
 
@@ -6374,6 +6500,9 @@
     /// the value of the current element
     json_value m_value = {};
 
+    /// the allocator to be used when constructing objects.
+    const allocator_type m_allocator;
+
 
   private:
     ///////////////
@@ -8735,16 +8864,18 @@
     {
       public:
         /// constructor for strings
-        parser(const string_t& s, const parser_callback_t cb = nullptr) noexcept
-            : callback(cb), m_lexer(s)
+        parser(const string_t& s, const parser_callback_t cb = nullptr,
+               const allocator_type& allocator = {}) noexcept
+            : callback(cb), m_lexer(s), m_allocator(allocator)
         {
             // read first token
             get_token();
         }
 
         /// a parser reading from an input stream
-        parser(std::istream& _is, const parser_callback_t cb = nullptr) noexcept
-            : callback(cb), m_lexer(&_is)
+        parser(std::istream& _is, const parser_callback_t cb = nullptr,
+               const allocator_type& allocator = {}) noexcept
+            : callback(cb), m_lexer(&_is), m_allocator(allocator)
         {
             // read first token
             get_token();
@@ -8776,7 +8907,7 @@
                     {
                         // explicitly set result to object to cope with {}
                         result.m_type = value_t::object;
-                        result.m_value = json_value(value_t::object);
+                        result.m_value = json_value(m_allocator, value_t::object);
                     }
 
                     // read next token
@@ -8852,9 +8983,9 @@
                 {
                     if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result))))
                     {
-                        // explicitly set result to object to cope with []
+                        // explicitly set result to array to cope with []
                         result.m_type = value_t::array;
-                        result.m_value = json_value(value_t::array);
+                        result.m_value = json_value(m_allocator, value_t::array);
                     }
 
                     // read next token
@@ -8996,6 +9127,8 @@
         typename lexer::token_type last_token = lexer::token_type::uninitialized;
         /// the lexer
         lexer m_lexer;
+        /// allocator for any objects that are created
+        const allocator_type m_allocator;
     };
 
   public:
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 537d4f4..e0cb669 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -269,9 +269,9 @@
     /*!
     @brief returns the allocator associated with the container
     */
-    static allocator_type get_allocator()
+    allocator_type get_allocator() const
     {
-        return allocator_type();
+        return m_allocator;
     }
 
 
@@ -373,6 +373,9 @@
           AllocatorType<std::pair<const StringType,
           basic_json>>>;
 
+    static_assert(std::is_member_function_pointer<decltype(&object_t::get_allocator)>::value,
+                  "object type is not allocator aware");
+
     /*!
     @brief a type for an array
 
@@ -419,6 +422,9 @@
     */
     using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
 
+    static_assert(std::is_member_function_pointer<decltype(&array_t::get_allocator)>::value,
+                  "array type is not allocator aware");
+
     /*!
     @brief a type for a string
 
@@ -466,6 +472,9 @@
     */
     using string_t = StringType;
 
+    static_assert(std::is_member_function_pointer<decltype(&string_t::get_allocator)>::value,
+                  "string type is not allocator aware");
+
     /*!
     @brief a type for a boolean
 
@@ -750,15 +759,17 @@
 
     /// helper for exception-safe object creation
     template<typename T, typename... Args>
-    static T* create(Args&& ... args)
+    static T* create(const allocator_type& allocator, Args&& ... args)
     {
-        AllocatorType<T> alloc;
+        AllocatorType<T> alloc(allocator);
         auto deleter = [&](T * object)
         {
-            alloc.deallocate(object, 1);
+            std::allocator_traits<AllocatorType<T>>::deallocate(alloc, object, 1);
         };
-        std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
-        alloc.construct(object.get(), std::forward<Args>(args)...);
+        std::unique_ptr<T, decltype(deleter)> object(std::allocator_traits<AllocatorType<T>>::allocate(
+                    alloc, 1), deleter);
+        std::allocator_traits<AllocatorType<T>>::construct(alloc, object.get(),
+                                             std::forward<Args>(args)...);
         assert(object.get() != nullptr);
         return object.release();
     }
@@ -819,25 +830,25 @@
         /// constructor for numbers (floating-point)
         json_value(number_float_t v) noexcept : number_float(v) {}
         /// constructor for empty values of a given type
-        json_value(value_t t)
+        json_value(const allocator_type& allocator, value_t t)
         {
             switch (t)
             {
                 case value_t::object:
                 {
-                    object = create<object_t>();
+                    object = create<object_t>(allocator, allocator);
                     break;
                 }
 
                 case value_t::array:
                 {
-                    array = create<array_t>();
+                    array = create<array_t>(allocator, allocator);
                     break;
                 }
 
                 case value_t::string:
                 {
-                    string = create<string_t>("");
+                    string = create<string_t>(allocator, "");
                     break;
                 }
 
@@ -874,20 +885,35 @@
 
         /// constructor for strings
         json_value(const string_t& value)
+            : json_value(value.get_allocator(), value)
+        {}
+
+        /// constructor for strings
+        json_value(const allocator_type& allocator, const string_t& value)
         {
-            string = create<string_t>(value);
+            string = create<string_t>(allocator, value);
         }
 
         /// constructor for objects
         json_value(const object_t& value)
+            : json_value(value.get_allocator(), value)
+        {}
+
+        /// constructor for objects
+        json_value(const allocator_type& allocator, const object_t& value)
         {
-            object = create<object_t>(value);
+            object = create<object_t>(allocator, value, allocator);
         }
 
         /// constructor for arrays
         json_value(const array_t& value)
+            : json_value(value.get_allocator(), value)
+        {}
+
+        /// constructor for arrays
+        json_value(const allocator_type& allocator, const array_t& value)
         {
-            array = create<array_t>(value);
+            array = create<array_t>(allocator, value, allocator);
         }
     };
 
@@ -1005,6 +1031,7 @@
     array       | `[]`
 
     @param[in] value_type  the type of the value to create
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1028,8 +1055,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const value_t value_type)
-        : m_type(value_type), m_value(value_type)
+    basic_json(const value_t value_type,
+               const allocator_type& allocator = {})
+        : m_type(value_type),
+          m_value(allocator, value_type),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1038,6 +1068,8 @@
     Create a `null` JSON value. This is the implicit version of the `null`
     value constructor as it takes no parameters.
 
+    @param[in] allocator  the allocator to use to construct objects (optional)
+
     @complexity Constant.
 
     @exceptionsafety No-throw guarantee: this constructor never throws
@@ -1056,7 +1088,9 @@
 
     @since version 1.0.0
     */
-    basic_json() = default;
+    basic_json(const allocator_type& allocator = {}) noexcept
+        : m_allocator(allocator)
+    {}
 
     /*!
     @brief create a null object (explicitly)
@@ -1067,6 +1101,8 @@
     The passed null pointer itself is not read -- it is only used to choose
     the right constructor.
 
+    @param[in] allocator  the allocator to use to construct objects (optional)
+
     @complexity Constant.
 
     @exceptionsafety No-throw guarantee: this constructor never throws
@@ -1080,8 +1116,9 @@
 
     @since version 1.0.0
     */
-    basic_json(std::nullptr_t) noexcept
-        : basic_json(value_t::null)
+    basic_json(std::nullptr_t,
+               const allocator_type& allocator = {}) noexcept
+        : basic_json(value_t::null, allocator)
     {}
 
     /*!
@@ -1090,6 +1127,7 @@
     Create an object JSON value with a given content.
 
     @param[in] val  a value for the object
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1103,8 +1141,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const object_t& val)
-        : m_type(value_t::object), m_value(val)
+    basic_json(const object_t& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::object),
+          m_value(allocator, val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1121,6 +1162,7 @@
     basic_json value can be constructed.
 
     @param[in] val  a value for the object
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1138,12 +1180,17 @@
                   std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
                   std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
               = 0>
-    basic_json(const CompatibleObjectType& val)
-        : m_type(value_t::object)
+    basic_json(const CompatibleObjectType& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::object),
+          m_allocator(allocator)
     {
         using std::begin;
         using std::end;
-        m_value.object = create<object_t>(begin(val), end(val));
+        m_value.object = create<object_t>(m_allocator,
+                                          begin(val), end(val),
+                                          std::less<StringType>(),
+                                          m_allocator);
     }
 
     /*!
@@ -1152,6 +1199,7 @@
     Create an array JSON value with a given content.
 
     @param[in] val  a value for the array
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1165,8 +1213,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const array_t& val)
-        : m_type(value_t::array), m_value(val)
+    basic_json(const array_t& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::array),
+          m_value(allocator, val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1183,6 +1234,7 @@
     `value_type` from which a @ref basic_json value can be constructed.
 
     @param[in] val  a value for the array
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1205,12 +1257,16 @@
                   not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
                   std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type
               = 0>
-    basic_json(const CompatibleArrayType& val)
-        : m_type(value_t::array)
+    basic_json(const CompatibleArrayType& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::array),
+          m_allocator(allocator)
     {
         using std::begin;
         using std::end;
-        m_value.array = create<array_t>(begin(val), end(val));
+        m_value.array = create<array_t>(m_allocator,
+                                        begin(val), end(val),
+                                        m_allocator);
     }
 
     /*!
@@ -1219,6 +1275,7 @@
     Create an string JSON value with a given content.
 
     @param[in] val  a value for the string
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1234,8 +1291,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const string_t& val)
-        : m_type(value_t::string), m_value(val)
+    basic_json(const string_t& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::string),
+          m_value(allocator, val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1244,6 +1304,7 @@
     Create a string JSON value with a given content.
 
     @param[in] val  a literal value for the string
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1258,8 +1319,9 @@
 
     @since version 1.0.0
     */
-    basic_json(const typename string_t::value_type* val)
-        : basic_json(string_t(val))
+    basic_json(const typename string_t::value_type* val,
+               const allocator_type& allocator = {})
+        : basic_json(string_t(val, allocator), allocator)
     {}
 
     /*!
@@ -1268,6 +1330,7 @@
     Create a string JSON value with a given content.
 
     @param[in] val  a value for the string
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @tparam CompatibleStringType an string type which is compatible to @ref
     string_t, for instance `std::string`.
@@ -1289,8 +1352,9 @@
               std::enable_if<
                   std::is_constructible<string_t, CompatibleStringType>::value, int>::type
               = 0>
-    basic_json(const CompatibleStringType& val)
-        : basic_json(string_t(val))
+    basic_json(const CompatibleStringType& val,
+               const allocator_type& allocator = {})
+        : basic_json(string_t(val, allocator), allocator)
     {}
 
     /*!
@@ -1299,6 +1363,7 @@
     Creates a JSON boolean type from a given value.
 
     @param[in] val  a boolean value to store
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1307,8 +1372,11 @@
 
     @since version 1.0.0
     */
-    basic_json(boolean_t val) noexcept
-        : m_type(value_t::boolean), m_value(val)
+    basic_json(boolean_t val,
+               const allocator_type& allocator = {}) noexcept
+        : m_type(value_t::boolean),
+          m_value(val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1322,6 +1390,7 @@
     the helper type @a T is not visible in this constructor's interface.
 
     @param[in] val  an integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1340,8 +1409,11 @@
                  and std::is_same<T, number_integer_t>::value
                  , int>::type
              = 0>
-    basic_json(const number_integer_t val) noexcept
-        : m_type(value_t::number_integer), m_value(val)
+    basic_json(const number_integer_t val,
+               const allocator_type& allocator = {}) noexcept
+        : m_type(value_t::number_integer),
+          m_value(val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1350,6 +1422,7 @@
     Create an integer number JSON value with a given content.
 
     @param[in] val  an integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @note This constructor allows to pass enums directly to a constructor. As
     C++ has no way of specifying the type of an anonymous enum explicitly, we
@@ -1369,9 +1442,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const int val) noexcept
+    basic_json(const int val,
+               const allocator_type& allocator = {}) noexcept
         : m_type(value_t::number_integer),
-          m_value(static_cast<number_integer_t>(val))
+          m_value(static_cast<number_integer_t>(val)),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1386,6 +1461,7 @@
     `long`, and `short`.
 
     @param[in] val  an integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1406,9 +1482,11 @@
                  std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
                  CompatibleNumberIntegerType>::type
              = 0>
-    basic_json(const CompatibleNumberIntegerType val) noexcept
+    basic_json(const CompatibleNumberIntegerType val,
+               const allocator_type& allocator = {}) noexcept
         : m_type(value_t::number_integer),
-          m_value(static_cast<number_integer_t>(val))
+          m_value(static_cast<number_integer_t>(val)),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1420,6 +1498,7 @@
     visible in) the interface.
 
     @param[in] val  an integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1434,8 +1513,11 @@
                  and std::is_same<T, number_unsigned_t>::value
                  , int>::type
              = 0>
-    basic_json(const number_unsigned_t val) noexcept
-        : m_type(value_t::number_unsigned), m_value(val)
+    basic_json(const number_unsigned_t val,
+               const allocator_type& allocator = {}) noexcept
+        : m_type(value_t::number_unsigned),
+          m_value(val),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1450,6 +1532,7 @@
     `uint32_t`, or `unsigned short`.
 
     @param[in] val  an unsigned integer to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Constant.
 
@@ -1465,9 +1548,11 @@
                   not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
                   CompatibleNumberUnsignedType>::type
               = 0>
-    basic_json(const CompatibleNumberUnsignedType val) noexcept
+    basic_json(const CompatibleNumberUnsignedType val,
+               const allocator_type& allocator = {}) noexcept
         : m_type(value_t::number_unsigned),
-          m_value(static_cast<number_unsigned_t>(val))
+          m_value(static_cast<number_unsigned_t>(val)),
+          m_allocator(allocator)
     {}
 
     /*!
@@ -1476,6 +1561,7 @@
     Create a floating-point number JSON value with a given content.
 
     @param[in] val  a floating-point value to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
     disallows NaN values:
@@ -1494,8 +1580,11 @@
 
     @since version 1.0.0
     */
-    basic_json(const number_float_t val) noexcept
-        : m_type(value_t::number_float), m_value(val)
+    basic_json(const number_float_t val,
+               const allocator_type& allocator = {}) noexcept
+        : m_type(value_t::number_float),
+          m_value(val),
+          m_allocator(allocator)
     {
         // replace infinity and NAN by null
         if (not std::isfinite(val))
@@ -1517,6 +1606,7 @@
     or `double`.
 
     @param[in] val  a floating-point to create a JSON number from
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
     disallows NaN values:
@@ -1541,8 +1631,9 @@
                  std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
                  std::is_floating_point<CompatibleNumberFloatType>::value>::type
              >
-    basic_json(const CompatibleNumberFloatType val) noexcept
-        : basic_json(number_float_t(val))
+    basic_json(const CompatibleNumberFloatType val,
+               const allocator_type& allocator = {}) noexcept
+        : basic_json(number_float_t(val), allocator)
     {}
 
     /*!
@@ -1597,6 +1688,8 @@
     value_t::array and @ref value_t::object are valid); when @a type_deduction
     is set to `true`, this parameter has no effect
 
+    @param[in] allocator  the allocator to use to construct objects (optional)
+
     @throw std::domain_error if @a type_deduction is `false`, @a manual_type
     is `value_t::object`, but @a init contains an element which is not a pair
     whose first element is a string; example: `"cannot create object from
@@ -1616,7 +1709,9 @@
     */
     basic_json(std::initializer_list<basic_json> init,
                bool type_deduction = true,
-               value_t manual_type = value_t::array)
+               value_t manual_type = value_t::array,
+               const allocator_type& allocator = {})
+        : m_allocator(allocator)
     {
         // check if each element is an array with two elements whose first
         // element is a string
@@ -1646,7 +1741,7 @@
         {
             // the initializer list is a list of pairs -> create object
             m_type = value_t::object;
-            m_value = value_t::object;
+            m_value = json_value(m_allocator, value_t::object);
 
             assert(m_value.object != nullptr);
 
@@ -1659,7 +1754,7 @@
         {
             // the initializer list describes an array -> create array
             m_type = value_t::array;
-            m_value.array = create<array_t>(init);
+            m_value.array = create<array_t>(m_allocator, init, m_allocator);
         }
     }
 
@@ -1682,6 +1777,7 @@
 
     @param[in] init  initializer list with JSON values to create an array from
     (optional)
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @return JSON array value
 
@@ -1698,9 +1794,10 @@
     @since version 1.0.0
     */
     static basic_json array(std::initializer_list<basic_json> init =
-                                std::initializer_list<basic_json>())
+                                std::initializer_list<basic_json>(),
+                            const allocator_type& allocator = {})
     {
-        return basic_json(init, false, value_t::array);
+        return basic_json(init, false, value_t::array, allocator);
     }
 
     /*!
@@ -1718,6 +1815,7 @@
     value_t).
 
     @param[in] init  initializer list to create an object from (optional)
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @return JSON object value
 
@@ -1738,9 +1836,10 @@
     @since version 1.0.0
     */
     static basic_json object(std::initializer_list<basic_json> init =
-                                 std::initializer_list<basic_json>())
+                                 std::initializer_list<basic_json>(),
+                             const allocator_type& allocator = {})
     {
-        return basic_json(init, false, value_t::object);
+        return basic_json(init, false, value_t::object, allocator);
     }
 
     /*!
@@ -1752,6 +1851,7 @@
 
     @param[in] cnt  the number of JSON copies of @a val to create
     @param[in] val  the JSON value to copy
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in @a cnt.
 
@@ -1761,10 +1861,12 @@
 
     @since version 1.0.0
     */
-    basic_json(size_type cnt, const basic_json& val)
-        : m_type(value_t::array)
+    basic_json(size_type cnt, const basic_json& val,
+               const allocator_type& allocator = {})
+        : m_type(value_t::array),
+          m_allocator(allocator)
     {
-        m_value.array = create<array_t>(cnt, val);
+        m_value.array = create<array_t>(m_allocator, cnt, val, m_allocator);
     }
 
     /*!
@@ -1784,6 +1886,7 @@
 
     @param[in] first begin of the range to copy from (included)
     @param[in] last end of the range to copy from (excluded)
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @throw std::domain_error if iterators are not compatible; that is, do not
     belong to the same JSON value; example: `"iterators are not compatible"`
@@ -1807,7 +1910,10 @@
                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value
                   , int>::type
               = 0>
-    basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
+    basic_json(InputIT first, InputIT last,
+               const allocator_type& allocator = {})
+        : m_type(first.m_object->m_type),
+          m_allocator(allocator)
     {
         // make sure iterator fits the current value
         if (first.m_object != last.m_object)
@@ -1876,13 +1982,20 @@
 
             case value_t::object:
             {
-                m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
+                m_value.object = create<object_t>(m_allocator,
+                                                  first.m_it.object_iterator,
+                                                  last.m_it.object_iterator,
+                                                  std::less<StringType>(),
+                                                  m_allocator);
                 break;
             }
 
             case value_t::array:
             {
-                m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
+                m_value.array = create<array_t>(m_allocator,
+                                                first.m_it.array_iterator,
+                                                last.m_it.array_iterator,
+                                                m_allocator);
                 break;
             }
 
@@ -1901,6 +2014,7 @@
     @param[in] cb a parser callback function of type @ref parser_callback_t
     which is used to control the deserialization by filtering unwanted values
     (optional)
+    @param[in] allocator  the allocator to use to construct objects (optional)
 
     @complexity Linear in the length of the input. The parser is a predictive
     LL(1) parser. The complexity can be higher if the parser callback function
@@ -1914,9 +2028,11 @@
 
     @since version 2.0.0
     */
-    explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr)
+    explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr,
+                        const allocator_type& allocator = {})
+        : m_allocator(allocator)
     {
-        *this = parser(i, cb).parse();
+        *this = parser(i, cb, allocator).parse();
     }
 
     ///////////////////////////////////////
@@ -1946,7 +2062,8 @@
     @since version 1.0.0
     */
     basic_json(const basic_json& other)
-        : m_type(other.m_type)
+        : m_type(other.m_type),
+          m_allocator(other.m_allocator)
     {
         switch (m_type)
         {
@@ -2022,7 +2139,8 @@
     */
     basic_json(basic_json&& other) noexcept
         : m_type(std::move(other.m_type)),
-          m_value(std::move(other.m_value))
+          m_value(std::move(other.m_value)),
+          m_allocator(std::move(other.m_allocator))
     {
         // invalidate payload
         other.m_type = value_t::null;
@@ -2086,25 +2204,25 @@
         {
             case value_t::object:
             {
-                AllocatorType<object_t> alloc;
-                alloc.destroy(m_value.object);
-                alloc.deallocate(m_value.object, 1);
+                AllocatorType<object_t> alloc(m_allocator);
+                std::allocator_traits<AllocatorType<object_t>>::destroy(alloc, m_value.object);
+                std::allocator_traits<AllocatorType<object_t>>::deallocate(alloc, m_value.object, 1);
                 break;
             }
 
             case value_t::array:
             {
-                AllocatorType<array_t> alloc;
-                alloc.destroy(m_value.array);
-                alloc.deallocate(m_value.array, 1);
+                AllocatorType<array_t> alloc(m_allocator);
+                std::allocator_traits<AllocatorType<array_t>>::destroy(alloc, m_value.array);
+                std::allocator_traits<AllocatorType<array_t>>::deallocate(alloc, m_value.array, 1);
                 break;
             }
 
             case value_t::string:
             {
-                AllocatorType<string_t> alloc;
-                alloc.destroy(m_value.string);
-                alloc.deallocate(m_value.string, 1);
+                AllocatorType<string_t> alloc(m_allocator);
+                std::allocator_traits<AllocatorType<string_t>>::destroy(alloc, m_value.string);
+                std::allocator_traits<AllocatorType<string_t>>::deallocate(alloc, m_value.string, 1);
                 break;
             }
 
@@ -2152,7 +2270,10 @@
     */
     string_t dump(const int indent = -1) const
     {
-        std::stringstream ss;
+        std::basic_stringstream<typename string_t::value_type,
+            typename string_t::traits_type,
+            typename string_t::allocator_type> ss;
+
         // fix locale problems
         ss.imbue(std::locale(std::locale(), new DecimalSeparator));
 
@@ -3327,7 +3448,7 @@
         if (is_null())
         {
             m_type = value_t::array;
-            m_value.array = create<array_t>();
+            m_value.array = create<array_t>(m_allocator, m_allocator);
         }
 
         // operator[] only works for arrays
@@ -3416,7 +3537,7 @@
         if (is_null())
         {
             m_type = value_t::object;
-            m_value.object = create<object_t>();
+            m_value.object = create<object_t>(m_allocator, m_allocator);
         }
 
         // operator[] only works for objects
@@ -3575,7 +3696,7 @@
         if (is_null())
         {
             m_type = value_t::object;
-            m_value = value_t::object;
+            m_value = json_value(m_allocator, value_t::object);
         }
 
         // at only works for objects
@@ -4906,7 +5027,7 @@
         if (is_null())
         {
             m_type = value_t::array;
-            m_value = value_t::array;
+            m_value = json_value(m_allocator, value_t::array);
         }
 
         // add element to array (move semantics)
@@ -4942,7 +5063,7 @@
         if (is_null())
         {
             m_type = value_t::array;
-            m_value = value_t::array;
+            m_value = json_value(m_allocator, value_t::array);
         }
 
         // add element to array
@@ -4992,7 +5113,7 @@
         if (is_null())
         {
             m_type = value_t::object;
-            m_value = value_t::object;
+            m_value = json_value(m_allocator, value_t::object);
         }
 
         // add element to array
@@ -5896,6 +6017,7 @@
     @param[in] cb a parser callback function of type @ref parser_callback_t
     which is used to control the deserialization by filtering unwanted values
     (optional)
+    @param[in] allocator the allocator to use to construct objects (optional)
 
     @return result of the deserialization
 
@@ -5914,9 +6036,10 @@
     @since version 1.0.0
     */
     static basic_json parse(const string_t& s,
-                            const parser_callback_t cb = nullptr)
+                            const parser_callback_t cb = nullptr,
+                            const allocator_type& allocator = {})
     {
-        return parser(s, cb).parse();
+        return parser(s, cb, allocator).parse();
     }
 
     /*!
@@ -5926,6 +6049,7 @@
     @param[in] cb a parser callback function of type @ref parser_callback_t
     which is used to control the deserialization by filtering unwanted values
     (optional)
+    @param[in] allocator the allocator to use to construct objects (optional)
 
     @return result of the deserialization
 
@@ -5944,18 +6068,20 @@
     @since version 1.0.0
     */
     static basic_json parse(std::istream& i,
-                            const parser_callback_t cb = nullptr)
+                            const parser_callback_t cb = nullptr,
+                            const allocator_type& allocator = {})
     {
-        return parser(i, cb).parse();
+        return parser(i, cb, allocator).parse();
     }
 
     /*!
     @copydoc parse(std::istream&, const parser_callback_t)
     */
     static basic_json parse(std::istream&& i,
-                            const parser_callback_t cb = nullptr)
+                            const parser_callback_t cb = nullptr,
+                            const allocator_type& allocator = {})
     {
-        return parser(i, cb).parse();
+        return parser(i, cb, allocator).parse();
     }
 
     /*!
@@ -5983,7 +6109,7 @@
     */
     friend std::istream& operator<<(basic_json& j, std::istream& i)
     {
-        j = parser(i).parse();
+        j = parser(i, nullptr, j.get_allocator()).parse();
         return i;
     }
 
@@ -5993,7 +6119,7 @@
     */
     friend std::istream& operator>>(std::istream& i, basic_json& j)
     {
-        j = parser(i).parse();
+        j = parser(i, nullptr, j.get_allocator()).parse();
         return i;
     }
 
@@ -6374,6 +6500,9 @@
     /// the value of the current element
     json_value m_value = {};
 
+    /// the allocator to be used when constructing objects.
+    const allocator_type m_allocator;
+
 
   private:
     ///////////////
@@ -8032,16 +8161,18 @@
     {
       public:
         /// constructor for strings
-        parser(const string_t& s, const parser_callback_t cb = nullptr) noexcept
-            : callback(cb), m_lexer(s)
+        parser(const string_t& s, const parser_callback_t cb = nullptr,
+               const allocator_type& allocator = {}) noexcept
+            : callback(cb), m_lexer(s), m_allocator(allocator)
         {
             // read first token
             get_token();
         }
 
         /// a parser reading from an input stream
-        parser(std::istream& _is, const parser_callback_t cb = nullptr) noexcept
-            : callback(cb), m_lexer(&_is)
+        parser(std::istream& _is, const parser_callback_t cb = nullptr,
+               const allocator_type& allocator = {}) noexcept
+            : callback(cb), m_lexer(&_is), m_allocator(allocator)
         {
             // read first token
             get_token();
@@ -8073,7 +8204,7 @@
                     {
                         // explicitly set result to object to cope with {}
                         result.m_type = value_t::object;
-                        result.m_value = json_value(value_t::object);
+                        result.m_value = json_value(m_allocator, value_t::object);
                     }
 
                     // read next token
@@ -8149,9 +8280,9 @@
                 {
                     if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result))))
                     {
-                        // explicitly set result to object to cope with []
+                        // explicitly set result to array to cope with []
                         result.m_type = value_t::array;
-                        result.m_value = json_value(value_t::array);
+                        result.m_value = json_value(m_allocator, value_t::array);
                     }
 
                     // read next token
@@ -8293,6 +8424,8 @@
         typename lexer::token_type last_token = lexer::token_type::uninitialized;
         /// the lexer
         lexer m_lexer;
+        /// allocator for any objects that are created
+        const allocator_type m_allocator;
     };
 
   public:
diff --git a/test/src/StlAllocatorMock.hpp b/test/src/StlAllocatorMock.hpp
new file mode 100644
index 0000000..43ad450
--- /dev/null
+++ b/test/src/StlAllocatorMock.hpp
@@ -0,0 +1,122 @@
+#pragma once
+
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "StlAllocatorMockState.hpp"
+
+template <class T>
+class StlAllocatorMock
+{
+  public:
+    typedef typename std::remove_const<T>::type value_type;
+
+    typedef size_t size_type;
+    typedef ptrdiff_t difference_type;
+    typedef value_type* pointer;
+    typedef const value_type* const_pointer;
+    typedef value_type& reference;
+    typedef const value_type& const_reference;
+
+    template <class U> struct rebind
+    {
+        typedef StlAllocatorMock<U> other;
+    };
+
+    // The default constructor is deleted to detect any cases where the state
+    // of the allocator will be lost.
+    // TODO: Uncomment this to find incorrect uses of the constructor.
+    //StlAllocatorMock() = delete;
+    StlAllocatorMock()
+    {
+        FAIL("default constructor should not be used");
+    }
+
+    explicit StlAllocatorMock(const StlAllocatorMockState* pState)
+        : m_pState(pState)
+    {}
+
+    template <class U>
+    StlAllocatorMock(const StlAllocatorMock<U>& stlAllocator)
+        : m_pState(stlAllocator.m_pState)
+    {}
+
+    StlAllocatorMock(const StlAllocatorMock& stlAllocator)
+        : m_pState(stlAllocator.m_pState)
+    {}
+
+    StlAllocatorMock& operator=(const StlAllocatorMock& rhs)
+    {
+        if (this != &rhs)
+        {
+            m_pState = rhs.m_pState;
+        }
+        return *this;
+    }
+
+    ~StlAllocatorMock()
+    {}
+
+    pointer address(reference x) const
+    {
+        return std::addressof(x);
+    }
+
+    const_pointer address(const_reference x) const
+    {
+        return std::addressof(x);
+    }
+
+    pointer allocate(size_type count, const void* = nullptr)
+    {
+        pointer ptr = static_cast<pointer>(m_pState->Allocate(sizeof(T) * count));
+
+        if (nullptr == ptr)
+        {
+            throw std::bad_alloc();
+        }
+
+        return ptr;
+    }
+
+    void deallocate(pointer p, size_type = 0)
+    {
+        m_pState->Free(p);
+    }
+
+    template <class U>
+    void construct(pointer p, U&& val)
+    {
+        new(reinterpret_cast<void*>(p)) T(std::forward<U>(val));
+    }
+
+    size_type max_size() const
+    {
+        size_type count = std::numeric_limits<size_type>::max() / sizeof(T);
+        return count > 0 ? count : 1;
+    }
+
+    void destroy(const_pointer p)
+    {
+        p->~T();
+    }
+
+    bool operator==(const StlAllocatorMock& rhs) const
+    {
+        return *m_pState == *rhs.m_pState;
+    }
+
+    bool operator!=(const StlAllocatorMock& rhs) const
+    {
+        return !(this->operator==(rhs));
+    }
+
+  private:
+    // Required to allow the copy instructor for a different templated type to
+    // access the private members of this class.
+    template <typename U>
+    friend class StlAllocatorMock;
+
+    const StlAllocatorMockState* m_pState = nullptr;
+};
diff --git a/test/src/StlAllocatorMockState.hpp b/test/src/StlAllocatorMockState.hpp
new file mode 100644
index 0000000..fe133b6
--- /dev/null
+++ b/test/src/StlAllocatorMockState.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <set>
+
+class StlAllocatorMockState
+{
+  public:
+
+    StlAllocatorMockState(bool failAllAllocations = false)
+        : m_allocatedBlocks(), m_failAllAllocations(failAllAllocations)
+    {}
+
+    ~StlAllocatorMockState()
+    {
+        AssertNoOutstandingBlocks();
+    }
+
+    void* Allocate(const size_t cb) const
+    {
+        if (m_failAllAllocations)
+        {
+            return nullptr;
+        }
+
+        void* pBlock = ::malloc(cb);
+        m_allocatedBlocks.emplace(pBlock);
+        return pBlock;
+    }
+
+    void Free(void* pv) const
+    {
+        if (0 == m_allocatedBlocks.erase(pv))
+        {
+            throw "Free of unknown block";
+        }
+
+        ::free(pv);
+    }
+
+    void AssertNoOutstandingBlocks() const
+    {
+        CHECK(m_allocatedBlocks.empty());
+    }
+
+    bool operator==(const StlAllocatorMockState& rhs) const
+    {
+        return this == &rhs;
+    }
+
+  private:
+    mutable std::set<void*> m_allocatedBlocks;
+    const bool m_failAllAllocations;
+};
diff --git a/test/src/unit.cpp b/test/src/unit.cpp
index edbafac..ff82ebd 100644
--- a/test/src/unit.cpp
+++ b/test/src/unit.cpp
@@ -40,15 +40,29 @@
 #include <unordered_set>
 #include <vector>
 
-#define private public
-#include "json.hpp"
-using nlohmann::json;
-
 // disable float-equal warnings on GCC/clang
 #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
     #pragma GCC diagnostic ignored "-Wfloat-equal"
 #endif
 
+#define private public
+#include "json.hpp"
+using nlohmann::json;
+
+#include "StlAllocatorMock.hpp"
+using string_with_allocator =
+    std::basic_string<char, std::char_traits<char>, StlAllocatorMock<char>>;
+
+using json_with_allocator = nlohmann::basic_json <
+                            std::map,
+                            std::vector,
+                            string_with_allocator,
+                            bool,
+                            std::int64_t,
+                            std::uint64_t,
+                            double,
+                            StlAllocatorMock >;
+
 TEST_CASE("constructors")
 {
     SECTION("create an empty value with a given type")
@@ -150,6 +164,22 @@
             json j(o);
             CHECK(j.type() == json::value_t::object);
         }
+
+        SECTION("filled object (custom allocator)")
+        {
+            StlAllocatorMockState allocatorState;
+            StlAllocatorMock<json_with_allocator> allocator(&allocatorState);
+
+            json_with_allocator::object_t o(allocator);
+            o.insert({json_with_allocator::string_t("a", allocator), json_with_allocator(1, allocator)});
+            o.insert({json_with_allocator::string_t("b", allocator), json_with_allocator(1u, allocator)});
+            o.insert({json_with_allocator::string_t("c", allocator), json_with_allocator(2.2, allocator)});
+            o.insert({json_with_allocator::string_t("d", allocator), json_with_allocator(false, allocator)});
+            o.insert({json_with_allocator::string_t("e", allocator), json_with_allocator("string", allocator)});
+            o.insert({json_with_allocator::string_t("f", allocator), json_with_allocator(allocator)});
+            json_with_allocator j(o, allocator);
+            CHECK((j.type() == json_with_allocator::value_t::object));
+        }
     }
 
     SECTION("create an object (implicit)")
@@ -221,6 +251,24 @@
             json j(a);
             CHECK(j.type() == json::value_t::array);
         }
+
+        SECTION("filled array (custom allocator)")
+        {
+            StlAllocatorMockState allocatorState;
+            StlAllocatorMock<json_with_allocator> allocator(&allocatorState);
+
+            json_with_allocator::array_t a({json_with_allocator(1, allocator),
+                                            json_with_allocator(1u, allocator),
+                                            json_with_allocator(2.2, allocator),
+                                            json_with_allocator(false, allocator),
+                                            json_with_allocator("string", allocator),
+                                            json_with_allocator(allocator)
+                                           },
+                                           allocator);
+            json_with_allocator j(a, allocator);
+
+            CHECK((j.type() == json_with_allocator::value_t::array));
+        }
     }
 
     SECTION("create an array (implicit)")
@@ -308,6 +356,17 @@
             json j(s);
             CHECK(j.type() == json::value_t::string);
         }
+
+        SECTION("filled string (custom allocator)")
+        {
+            StlAllocatorMockState allocatorState;
+            StlAllocatorMock<json_with_allocator> allocator(&allocatorState);
+
+            json_with_allocator::string_t s("Hello world", allocator);
+            json_with_allocator j(s, allocator);
+
+            CHECK((j.type() == json_with_allocator::value_t::string));
+        }
     }
 
     SECTION("create a string (implicit)")
@@ -966,7 +1025,7 @@
     SECTION("create an array of n copies of a given value")
     {
         json v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}};
-        json arr(3, v);
+        json arr(static_cast<size_t>(3), v);
         CHECK(arr.size() == 3);
         for (auto& x : arr)
         {
@@ -1686,6 +1745,17 @@
             CHECK(j_discarded.dump() == "<discarded>");
         }
 
+        /*
+                SECTION("no indent (custom allocator)")
+                {
+                    StlAllocatorMockState allocatorState;
+                    StlAllocatorMock<json_with_allocator> allocator(&allocatorState);
+
+                    json_with_allocator ja(allocator);
+                    ja.dump();
+                }
+                */
+
         SECTION("check that precision is reset after serialization")
         {
             // create stringstream and set precision
@@ -8862,6 +8932,16 @@
     {
         CHECK("[\"foo\",1,2,3,false,{\"one\":1}]"_json == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
     }
+
+    /*
+        SECTION("string (custom allocator)")
+        {
+            StlAllocatorMockState allocatorState;
+            StlAllocatorMock<json_with_allocator> allocator(&allocatorState);
+
+            json_with_allocator j = json_with_allocator::parse("[]");
+        }
+        */
 }
 
 TEST_CASE("iterator class")
@@ -14375,8 +14455,32 @@
     }
 }
 
-// special test case to check if memory is leaked if constructor throws
+TEST_CASE("custom Allocators")
+{
+    SECTION("constructor with state persists state")
+    {
+        StlAllocatorMockState allocatorState;
+        StlAllocatorMock<json_with_allocator> originalAllocator(&allocatorState);
 
+        json_with_allocator j(originalAllocator);
+        StlAllocatorMock<json_with_allocator> finalAllocator = j.get_allocator();
+
+        CHECK(originalAllocator == finalAllocator);
+    }
+
+    SECTION("bad_alloc thrown when allocation fails")
+    {
+        // Create a state that will fail all allocations.
+        StlAllocatorMockState allocatorState(true);
+        StlAllocatorMock<json_with_allocator> allocator(&allocatorState);
+
+        // creating an object should throw
+        CHECK_THROWS_AS(json_with_allocator j(json_with_allocator::value_t::object, allocator),
+                        std::bad_alloc);
+    }
+}
+
+// special test case to check if memory is leaked if constructor throws
 template<class T>
 struct my_allocator : std::allocator<T>
 {
@@ -14385,6 +14489,9 @@
     {
         throw std::bad_alloc();
     }
+
+    my_allocator() = default;
+    template <class U> my_allocator(const my_allocator<U>&) {}
 };
 
 TEST_CASE("bad_alloc")