diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp
index c666d295c..3faa8397c 100644
--- a/Machines/AmstradCPC/AmstradCPC.cpp
+++ b/Machines/AmstradCPC/AmstradCPC.cpp
@@ -902,7 +902,7 @@ class ConcreteMachine:
 
 			// Type whatever is required.
 			if(target.loading_command.length()) {
-				set_typer_for_string(target.loading_command.c_str());
+				type_string(target.loading_command);
 			}
 
 			insert_media(target.media);
@@ -953,9 +953,9 @@ class ConcreteMachine:
 
 // MARK: - Keyboard
 
-		void set_typer_for_string(const char *string) override final {
+		void type_string(const std::string &string) override final {
 			std::unique_ptr<CharacterMapper> mapper(new CharacterMapper());
-			Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
+			Utility::TypeRecipient::add_typer(string, std::move(mapper));
 		}
 
 		HalfCycles get_typer_delay() override final {
diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp
index 6d8e70ceb..c1b5825e6 100644
--- a/Machines/Commodore/Vic-20/Vic20.cpp
+++ b/Machines/Commodore/Vic-20/Vic20.cpp
@@ -348,7 +348,7 @@ class ConcreteMachine:
 
 		void configure_as_target(const StaticAnalyser::Target &target) override final {
 			if(target.loading_command.length()) {
-				set_typer_for_string(target.loading_command.c_str());
+				type_string(target.loading_command);
 			}
 
 			switch(target.vic20.memory_model) {
@@ -653,9 +653,9 @@ class ConcreteMachine:
 			m6502_.set_irq_line(keyboard_via_.get_interrupt_line());
 		}
 
-		void set_typer_for_string(const char *string) override final {
+		void type_string(const std::string &string) override final {
 			std::unique_ptr<CharacterMapper> mapper(new CharacterMapper());
-			Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
+			Utility::TypeRecipient::add_typer(string, std::move(mapper));
 		}
 
 		void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape) override final {
diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp
index ec56ccc1b..738b820d3 100644
--- a/Machines/Electron/Electron.cpp
+++ b/Machines/Electron/Electron.cpp
@@ -115,7 +115,7 @@ class ConcreteMachine:
 
 		void configure_as_target(const StaticAnalyser::Target &target) override final {
 			if(target.loading_command.length()) {
-				set_typer_for_string(target.loading_command.c_str());
+				type_string(target.loading_command);
 			}
 
 			if(target.acorn.should_shift_restart) {
@@ -414,9 +414,9 @@ class ConcreteMachine:
 			return Cycles(625*128*2);	// accept a new character every two frames
 		}
 
-		void set_typer_for_string(const char *string) override final {
+		void type_string(const std::string &string) override final {
 			std::unique_ptr<CharacterMapper> mapper(new CharacterMapper());
-			Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
+			Utility::TypeRecipient::add_typer(string, std::move(mapper));
 		}
 
 		KeyboardMapper &get_keyboard_mapper() override {
diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp
index dc07c1e15..63e7abb5c 100644
--- a/Machines/Oric/Oric.cpp
+++ b/Machines/Oric/Oric.cpp
@@ -262,7 +262,7 @@ class ConcreteMachine:
 			}
 
 			if(target.loading_command.length()) {
-				set_typer_for_string(target.loading_command.c_str());
+				type_string(target.loading_command);
 			}
 
 			if(target.oric.use_atmos_rom) {
@@ -407,9 +407,9 @@ class ConcreteMachine:
 		}
 
 		// for Utility::TypeRecipient::Delegate
-		void set_typer_for_string(const char *string) override final {
+		void type_string(const std::string &string) override final {
 			std::unique_ptr<CharacterMapper> mapper(new CharacterMapper);
-			Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
+			Utility::TypeRecipient::add_typer(string, std::move(mapper));
 		}
 
 		// for Microdisc::Delegate
diff --git a/Machines/Utility/Typer.cpp b/Machines/Utility/Typer.cpp
index 4160af136..09aa5585c 100644
--- a/Machines/Utility/Typer.cpp
+++ b/Machines/Utility/Typer.cpp
@@ -8,23 +8,22 @@
 
 #include "Typer.hpp"
 
-#include <cstdlib>
-#include <cstring>
+#include <sstream>
 
 using namespace Utility;
 
-Typer::Typer(const char *string, HalfCycles delay, HalfCycles frequency, std::unique_ptr<CharacterMapper> character_mapper, Delegate *delegate) :
+Typer::Typer(const std::string &string, HalfCycles delay, HalfCycles frequency, std::unique_ptr<CharacterMapper> character_mapper, Delegate *delegate) :
 		frequency_(frequency),
 		counter_(-delay),
 		delegate_(delegate),
 		character_mapper_(std::move(character_mapper)) {
-	std::size_t string_size = std::strlen(string) + 3;
-	string_ = (char *)std::malloc(string_size);
-	snprintf(string_, string_size, "%c%s%c", Typer::BeginString, string, Typer::EndString);
+	std::ostringstream string_stream;
+	string_stream << Typer::BeginString << string << Typer::EndString;
+	string_ = string_stream.str();
 }
 
 void Typer::run_for(const HalfCycles duration) {
-	if(string_) {
+	if(string_pointer_ < string_.size()) {
 		if(counter_ < 0 && counter_ + duration >= 0) {
 			if(!type_next_character()) {
 				delegate_->typer_reset(this);
@@ -32,7 +31,7 @@ void Typer::run_for(const HalfCycles duration) {
 		}
 
 		counter_ += duration;
-		while(string_ && counter_ > frequency_) {
+		while(string_pointer_ < string_.size() && counter_ > frequency_) {
 			counter_ -= frequency_;
 			if(!type_next_character()) {
 				delegate_->typer_reset(this);
@@ -58,16 +57,10 @@ bool Typer::try_type_next_character() {
 }
 
 bool Typer::type_next_character() {
-	if(string_ == nullptr) return false;
+	if(string_pointer_ == string_.size()) return false;
 
 	if(!try_type_next_character()) {
 		phase_ = 0;
-		if(!string_[string_pointer_]) {
-			std::free(string_);
-			string_ = nullptr;
-			return false;
-		}
-
 		string_pointer_++;
 	} else {
 		phase_++;
@@ -76,10 +69,6 @@ bool Typer::type_next_character() {
 	return true;
 }
 
-Typer::~Typer() {
-	std::free(string_);
-}
-
 // MARK: - Character mapper
 
 uint16_t *CharacterMapper::table_lookup_sequence_for_character(KeySequence *sequences, std::size_t length, char character) {
diff --git a/Machines/Utility/Typer.hpp b/Machines/Utility/Typer.hpp
index 78f3e1668..2a7f22fc7 100644
--- a/Machines/Utility/Typer.hpp
+++ b/Machines/Utility/Typer.hpp
@@ -10,6 +10,8 @@
 #define Typer_hpp
 
 #include <memory>
+#include <string>
+
 #include "../KeyboardMachine.hpp"
 #include "../../ClockReceiver/ClockReceiver.hpp"
 
@@ -50,8 +52,7 @@ class Typer {
 				virtual void typer_reset(Typer *typer) = 0;
 		};
 
-		Typer(const char *string, HalfCycles delay, HalfCycles frequency, std::unique_ptr<CharacterMapper> character_mapper, Delegate *delegate);
-		~Typer();
+		Typer(const std::string &string, HalfCycles delay, HalfCycles frequency, std::unique_ptr<CharacterMapper> character_mapper, Delegate *delegate);
 
 		void run_for(const HalfCycles duration);
 		bool type_next_character();
@@ -62,7 +63,7 @@ class Typer {
 		const char EndString = 0x03;	// i.e. ASCII end of text
 
 	private:
-		char *string_;
+		std::string string_;
 		std::size_t string_pointer_ = 0;
 
 		HalfCycles frequency_;
@@ -82,7 +83,7 @@ class Typer {
 class TypeRecipient: public Typer::Delegate {
 	public:
 		/// Attaches a typer to this class that will type @c string using @c character_mapper as a source.
-		void set_typer_for_string(const char *string, std::unique_ptr<CharacterMapper> character_mapper) {
+		void add_typer(const std::string &string, std::unique_ptr<CharacterMapper> character_mapper) {
 			typer_.reset(new Typer(string, get_typer_delay(), get_typer_frequency(), std::move(character_mapper), this));
 		}
 
@@ -90,7 +91,7 @@ class TypeRecipient: public Typer::Delegate {
 			Provided as a hook for subclasses to implement so that external callers can install a typer
 			without needing inside knowledge as to where the character mapper comes from.
 		*/
-		virtual void set_typer_for_string(const char *string) = 0;
+		virtual void type_string(const std::string &) = 0;
 
 		/*!
 			Provided in order to conform to that part of the Typer::Delegate interface that goes above and
diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp
index 34ae4f312..3061726af 100644
--- a/Machines/ZX8081/ZX8081.cpp
+++ b/Machines/ZX8081/ZX8081.cpp
@@ -279,7 +279,7 @@ template<bool is_zx81> class ConcreteMachine:
 			Memory::Fuzz(ram_);
 
 			if(target.loading_command.length()) {
-				set_typer_for_string(target.loading_command.c_str());
+				type_string(target.loading_command);
 			}
 
 			insert_media(target.media);
@@ -293,9 +293,9 @@ template<bool is_zx81> class ConcreteMachine:
 			return !media.tapes.empty();
 		}
 
-		void set_typer_for_string(const char *string) override final {
+		void type_string(const std::string &string) override final {
 			std::unique_ptr<CharacterMapper> mapper(new CharacterMapper(is_zx81_));
-			Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
+			Utility::TypeRecipient::add_typer(string, std::move(mapper));
 		}
 
 		// Obtains the system ROMs.
diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm
index 9d8d25de5..fdf230241 100644
--- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm	
+++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm	
@@ -190,7 +190,7 @@ struct MachineDelegate: CRTMachine::Machine::Delegate, public LockProtectedDeleg
 - (void)paste:(NSString *)paste {
 	Utility::TypeRecipient *typeRecipient = _machine->type_recipient();
 	if(typeRecipient)
-		typeRecipient->set_typer_for_string([paste UTF8String]);
+		typeRecipient->type_string([paste UTF8String]);
 }
 
 - (void)applyTarget:(const StaticAnalyser::Target &)target {
diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp
index 4704b8106..03d6575cd 100644
--- a/OSBindings/SDL/main.cpp
+++ b/OSBindings/SDL/main.cpp
@@ -441,7 +441,7 @@ int main(int argc, char *argv[]) {
 					if(event.key.keysym.sym == SDLK_v && (SDL_GetModState()&KMOD_CTRL) && (SDL_GetModState()&KMOD_SHIFT)) {
 						Utility::TypeRecipient *type_recipient = machine->type_recipient();
 						if(type_recipient) {
-							type_recipient->set_typer_for_string(SDL_GetClipboardText());
+							type_recipient->type_string(SDL_GetClipboardText());
 							break;
 						}
 					}