diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp
index 46e79413ad..28e07023b8 100644
--- a/Source/Core/DolphinWX/InputConfigDiag.cpp
+++ b/Source/Core/DolphinWX/InputConfigDiag.cpp
@@ -218,8 +218,8 @@ void ControlDialog::UpdateListContents()
 {
   control_lbox->Clear();
 
-  ciface::Core::Device* const dev = g_controller_interface.FindDevice(m_devq);
-  if (dev)
+  const auto dev = g_controller_interface.FindDevice(m_devq);
+  if (dev != nullptr)
   {
     if (control_reference->is_input)
     {
@@ -493,8 +493,8 @@ void ControlDialog::DetectControl(wxCommandEvent& event)
   wxButton* const btn = (wxButton*)event.GetEventObject();
   const wxString lbl = btn->GetLabel();
 
-  ciface::Core::Device* const dev = g_controller_interface.FindDevice(m_devq);
-  if (dev)
+  const auto dev = g_controller_interface.FindDevice(m_devq);
+  if (dev != nullptr)
   {
     m_event_filter.BlockEvents(true);
     btn->SetLabel(_("[ waiting ]"));
@@ -502,7 +502,8 @@ void ControlDialog::DetectControl(wxCommandEvent& event)
     // This makes the "waiting" text work on Linux. true (only if needed) prevents crash on Windows
     wxTheApp->Yield(true);
 
-    ciface::Core::Device::Control* const ctrl = control_reference->Detect(DETECT_WAIT_TIME, dev);
+    ciface::Core::Device::Control* const ctrl =
+        control_reference->Detect(DETECT_WAIT_TIME, dev.get());
 
     // if we got input, select it in the list
     if (ctrl)
@@ -537,8 +538,8 @@ bool GamepadPage::DetectButton(ControlButton* button)
 {
   bool success = false;
   // find device :/
-  ciface::Core::Device* const dev = g_controller_interface.FindDevice(controller->default_device);
-  if (dev)
+  const auto dev = g_controller_interface.FindDevice(controller->default_device);
+  if (dev != nullptr)
   {
     m_event_filter.BlockEvents(true);
     button->SetLabel(_("[ waiting ]"));
@@ -547,7 +548,7 @@ bool GamepadPage::DetectButton(ControlButton* button)
     wxTheApp->Yield(true);
 
     ciface::Core::Device::Control* const ctrl =
-        button->control_reference->Detect(DETECT_WAIT_TIME, dev);
+        button->control_reference->Detect(DETECT_WAIT_TIME, dev.get());
 
     // if we got input, update expression and reference
     if (ctrl)
@@ -724,16 +725,12 @@ void GamepadPage::DeleteProfile(wxCommandEvent&)
 
 void InputConfigDialog::UpdateDeviceComboBox()
 {
-  ciface::Core::DeviceQualifier dq;
   for (GamepadPage* page : m_padpages)
   {
     page->device_cbox->Clear();
 
-    for (ciface::Core::Device* d : g_controller_interface.Devices())
-    {
-      dq.FromDevice(d);
-      page->device_cbox->Append(StrToWxStr(dq.ToString()));
-    }
+    for (const std::string& device_string : g_controller_interface.GetAllDeviceStrings())
+      page->device_cbox->Append(StrToWxStr(device_string));
 
     page->device_cbox->SetValue(StrToWxStr(page->controller->default_device.ToString()));
   }
diff --git a/Source/Core/InputCommon/ControllerEmu.cpp b/Source/Core/InputCommon/ControllerEmu.cpp
index 4d333e1d23..54d25748ad 100644
--- a/Source/Core/InputCommon/ControllerEmu.cpp
+++ b/Source/Core/InputCommon/ControllerEmu.cpp
@@ -242,9 +242,10 @@ void ControllerEmu::LoadDefaults(const ControllerInterface& ciface)
   IniFile::Section sec;
   LoadConfig(&sec);
 
-  if (ciface.Devices().size())
+  const std::string& default_device_string = g_controller_interface.GetDefaultDeviceString();
+  if (!default_device_string.empty())
   {
-    default_device.FromDevice(ciface.Devices()[0]);
+    default_device.FromString(default_device_string);
     UpdateDefaultDevice();
   }
 }
diff --git a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp
index f6957e3ca1..e36e314294 100644
--- a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp
@@ -13,7 +13,7 @@ namespace Android
 void Init()
 {
   for (int i = 0; i < 8; ++i)
-    g_controller_interface.AddDevice(new Touchscreen(i));
+    g_controller_interface.AddDevice(std::make_shared<Touchscreen>(i));
 }
 
 // Touchscreens and stuff
diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp
index b36387162d..cbf2c4dfbb 100644
--- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp
@@ -2,8 +2,10 @@
 // Licensed under GPLv2+
 // Refer to the license.txt file included.
 
-#include "InputCommon/ControllerInterface/ControllerInterface.h"
+#include <mutex>
+
 #include "Common/Thread.h"
+#include "InputCommon/ControllerInterface/ControllerInterface.h"
 
 #ifdef CIFACE_USE_XINPUT
 #include "InputCommon/ControllerInterface/XInput/XInput.h"
@@ -106,14 +108,11 @@ void ControllerInterface::Shutdown()
 
   std::lock_guard<std::mutex> lk(m_devices_mutex);
 
-  for (ciface::Core::Device* d : m_devices)
+  for (const auto& d : m_devices)
   {
     // Set outputs to ZERO before destroying device
     for (ciface::Core::Device::Output* o : d->Outputs())
       o->SetState(0);
-
-    // Delete device
-    delete d;
   }
 
   m_devices.clear();
@@ -141,10 +140,10 @@ void ControllerInterface::Shutdown()
   m_is_init = false;
 }
 
-void ControllerInterface::AddDevice(ciface::Core::Device* device)
+void ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device)
 {
   std::lock_guard<std::mutex> lk(m_devices_mutex);
-  m_devices.push_back(device);
+  m_devices.emplace_back(std::move(device));
 }
 
 //
@@ -155,7 +154,7 @@ void ControllerInterface::AddDevice(ciface::Core::Device* device)
 void ControllerInterface::UpdateInput()
 {
   std::lock_guard<std::mutex> lk(m_devices_mutex);
-  for (ciface::Core::Device* d : m_devices)
+  for (const auto& d : m_devices)
     d->UpdateInput();
 }
 
diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h
index 2571e5f3ab..2f4212ba85 100644
--- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h
+++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 #include <map>
-#include <mutex>
 #include <sstream>
 #include <string>
 #include <vector>
@@ -122,7 +121,7 @@ public:
   void Initialize(void* const hwnd);
   void Reinitialize();
   void Shutdown();
-  void AddDevice(ciface::Core::Device* device);
+  void AddDevice(std::shared_ptr<ciface::Core::Device> device);
   bool IsInit() const { return m_is_init; }
   void UpdateReference(ControlReference* control,
                        const ciface::Core::DeviceQualifier& default_device) const;
diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp
index ea059fde73..ecd1bf1d40 100644
--- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp
@@ -58,12 +58,10 @@ void InitJoystick(IDirectInput8* const idi8, HWND hwnd)
           }
         }
 
-        Joystick* js = new Joystick(/*&*i, */ js_device, name_counts[joystick.tszInstanceName]++);
+        auto js = std::make_shared<Joystick>(js_device, name_counts[joystick.tszInstanceName]++);
         // only add if it has some inputs/outputs
         if (js->Inputs().size() || js->Outputs().size())
-          g_controller_interface.AddDevice(js);
-        else
-          delete js;
+          g_controller_interface.AddDevice(std::move(js));
       }
       else
       {
diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp
index fc02238980..2ee0477653 100644
--- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp
@@ -51,7 +51,7 @@ void InitKeyboardMouse(IDirectInput8* const idi8, HWND _hwnd)
       SUCCEEDED(mo_device->SetDataFormat(&c_dfDIMouse2)) &&
       SUCCEEDED(mo_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))
   {
-    g_controller_interface.AddDevice(new KeyboardMouse(kb_device, mo_device));
+    g_controller_interface.AddDevice(std::make_shared<KeyboardMouse>(kb_device, mo_device));
     return;
   }
 
diff --git a/Source/Core/InputCommon/ControllerInterface/Device.cpp b/Source/Core/InputCommon/ControllerInterface/Device.cpp
index 7a3b8ac845..e47b04de99 100644
--- a/Source/Core/InputCommon/ControllerInterface/Device.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Device.cpp
@@ -144,17 +144,45 @@ bool DeviceQualifier::operator==(const DeviceQualifier& devq) const
   return false;
 }
 
-Device* DeviceContainer::FindDevice(const DeviceQualifier& devq) const
+std::shared_ptr<Device> DeviceContainer::FindDevice(const DeviceQualifier& devq) const
 {
-  for (Device* d : m_devices)
+  std::lock_guard<std::mutex> lk(m_devices_mutex);
+  for (const auto& d : m_devices)
   {
-    if (devq == d)
+    if (devq == d.get())
       return d;
   }
 
   return nullptr;
 }
 
+std::vector<std::string> DeviceContainer::GetAllDeviceStrings() const
+{
+  std::lock_guard<std::mutex> lk(m_devices_mutex);
+
+  std::vector<std::string> device_strings;
+  DeviceQualifier device_qualifier;
+
+  for (const auto& d : m_devices)
+  {
+    device_qualifier.FromDevice(d.get());
+    device_strings.emplace_back(device_qualifier.ToString());
+  }
+
+  return device_strings;
+}
+
+std::string DeviceContainer::GetDefaultDeviceString() const
+{
+  std::lock_guard<std::mutex> lk(m_devices_mutex);
+  if (m_devices.empty())
+    return "";
+
+  DeviceQualifier device_qualifier;
+  device_qualifier.FromDevice(m_devices[0].get());
+  return device_qualifier.ToString();
+}
+
 Device::Input* DeviceContainer::FindInput(const std::string& name, const Device* def_dev) const
 {
   if (def_dev)
@@ -164,7 +192,8 @@ Device::Input* DeviceContainer::FindInput(const std::string& name, const Device*
       return inp;
   }
 
-  for (Device* d : m_devices)
+  std::lock_guard<std::mutex> lk(m_devices_mutex);
+  for (const auto& d : m_devices)
   {
     Device::Input* const i = d->FindInput(name);
 
diff --git a/Source/Core/InputCommon/ControllerInterface/Device.h b/Source/Core/InputCommon/ControllerInterface/Device.h
index c3cddb3a79..23c499ec9d 100644
--- a/Source/Core/InputCommon/ControllerInterface/Device.h
+++ b/Source/Core/InputCommon/ControllerInterface/Device.h
@@ -164,12 +164,13 @@ public:
   Device::Input* FindInput(const std::string& name, const Device* def_dev) const;
   Device::Output* FindOutput(const std::string& name, const Device* def_dev) const;
 
-  const std::vector<Device*>& Devices() const { return m_devices; }
-  Device* FindDevice(const DeviceQualifier& devq) const;
+  std::vector<std::string> GetAllDeviceStrings() const;
+  std::string GetDefaultDeviceString() const;
+  std::shared_ptr<Device> FindDevice(const DeviceQualifier& devq) const;
 
 protected:
-  std::mutex m_devices_mutex;
-  std::vector<Device*> m_devices;
+  mutable std::mutex m_devices_mutex;
+  std::vector<std::shared_ptr<Device>> m_devices;
 };
 }
 }
diff --git a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp
index a87bdf8d35..7c916d108d 100644
--- a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp
@@ -333,7 +333,7 @@ public:
   operator std::string() override { return OpName(op) + "(" + (std::string)(*inner) + ")"; }
 };
 
-Device* ControlFinder::FindDevice(ControlQualifier qualifier)
+std::shared_ptr<Device> ControlFinder::FindDevice(ControlQualifier qualifier)
 {
   if (qualifier.has_device)
     return container.FindDevice(qualifier.device_qualifier);
@@ -343,7 +343,7 @@ Device* ControlFinder::FindDevice(ControlQualifier qualifier)
 
 Device::Control* ControlFinder::FindControl(ControlQualifier qualifier)
 {
-  Device* device = FindDevice(qualifier);
+  const std::shared_ptr<Device> device = FindDevice(qualifier);
   if (!device)
     return nullptr;
 
diff --git a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.h b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.h
index 6894c1924e..80904634e4 100644
--- a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.h
+++ b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.h
@@ -39,7 +39,7 @@ public:
   Core::Device::Control* FindControl(ControlQualifier qualifier);
 
 private:
-  Core::Device* FindDevice(ControlQualifier qualifier);
+  std::shared_ptr<Core::Device> FindDevice(ControlQualifier qualifier);
   const Core::DeviceContainer& container;
   const Core::DeviceQualifier& default_device;
   bool is_input;
diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm b/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm
index ea9723c6b9..48580cf98b 100644
--- a/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm
+++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm
@@ -144,7 +144,7 @@ static void DeviceMatching_callback(void* inContext, IOReturn inResult, void* in
   // Add a device if it's of a type we want
   if (IOHIDDeviceConformsTo(inIOHIDDeviceRef, kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard))
     g_controller_interface.AddDevice(
-        new Keyboard(inIOHIDDeviceRef, name, kbd_name_counts[name]++, g_window));
+        std::make_shared<Keyboard>(inIOHIDDeviceRef, name, kbd_name_counts[name]++, g_window));
 #if 0
 	else if (IOHIDDeviceConformsTo(inIOHIDDeviceRef,
 		kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse))
@@ -152,7 +152,8 @@ static void DeviceMatching_callback(void* inContext, IOReturn inResult, void* in
 			name, mouse_name_counts[name]++));
 #endif
   else
-    g_controller_interface.AddDevice(new Joystick(inIOHIDDeviceRef, name, joy_name_counts[name]++));
+    g_controller_interface.AddDevice(
+        std::make_shared<Joystick>(inIOHIDDeviceRef, name, joy_name_counts[name]++));
 }
 
 void Init(void* window)
diff --git a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp
index fc89d8a1e6..b361fee279 100644
--- a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp
@@ -61,7 +61,7 @@ void Init()
     int fd = open(child.physicalName.c_str(), O_RDONLY | O_NONBLOCK);
     if (fd < 0)
       continue;
-    g_controller_interface.AddDevice(new PipeDevice(fd, child.virtualName, found++));
+    g_controller_interface.AddDevice(std::make_shared<PipeDevice>(fd, child.virtualName, found++));
   }
 }
 
diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp
index 870f0387d7..a31abd3055 100644
--- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp
@@ -58,12 +58,10 @@ void Init()
     SDL_Joystick* dev = SDL_JoystickOpen(i);
     if (dev)
     {
-      Joystick* js = new Joystick(dev, i, name_counts[GetJoystickName(i)]++);
+      auto js = std::make_shared<Joystick>(dev, i, name_counts[GetJoystickName(i)]++);
       // only add if it has some inputs/outputs
       if (js->Inputs().size() || js->Outputs().size())
-        g_controller_interface.AddDevice(js);
-      else
-        delete js;
+        g_controller_interface.AddDevice(std::move(js));
     }
   }
 }
diff --git a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
index 982764d4b4..c36c3126f6 100644
--- a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
@@ -89,7 +89,7 @@ void Init()
   XINPUT_CAPABILITIES caps;
   for (int i = 0; i != 4; ++i)
     if (ERROR_SUCCESS == PXInputGetCapabilities(i, 0, &caps))
-      g_controller_interface.AddDevice(new Device(caps, i));
+      g_controller_interface.AddDevice(std::make_shared<Device>(caps, i));
 }
 
 void DeInit()
diff --git a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp
index d46f1cf4f6..c7c2e74242 100644
--- a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp
@@ -76,10 +76,12 @@ void Init(void* const hwnd)
   {
     current_master = &all_masters[i];
     if (current_master->use == XIMasterPointer)
+    {
       // Since current_master is a master pointer, its attachment must
       // be a master keyboard.
-      g_controller_interface.AddDevice(new KeyboardMouse(
+      g_controller_interface.AddDevice(std::make_shared<KeyboardMouse>(
           (Window)hwnd, xi_opcode, current_master->deviceid, current_master->attachment));
+    }
   }
 
   XCloseDisplay(dpy);
diff --git a/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.cpp b/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.cpp
index a7d94bbcd0..fd5cda04ec 100644
--- a/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.cpp
@@ -13,7 +13,7 @@ namespace Xlib
 {
 void Init(void* const hwnd)
 {
-  g_controller_interface.AddDevice(new KeyboardMouse((Window)hwnd));
+  g_controller_interface.AddDevice(std::make_shared<KeyboardMouse>((Window)hwnd));
 }
 
 KeyboardMouse::KeyboardMouse(Window window) : m_window(window)
diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
index 5da77e585a..658a442420 100644
--- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
@@ -68,18 +68,13 @@ void Init()
       // Unfortunately udev gives us no way to filter out the non event device interfaces.
       // So we open it and see if it works with evdev ioctls or not.
       std::string name = GetName(devnode);
-      evdevDevice* input = new evdevDevice(devnode, name_counts[name]++);
+      auto input = std::make_shared<evdevDevice>(devnode, name_counts[name]++);
 
       if (input->IsInteresting())
       {
-        g_controller_interface.AddDevice(input);
+        g_controller_interface.AddDevice(std::move(input));
         num_controllers++;
       }
-      else
-      {
-        // Either it wasn't a evdev device, or it didn't have at least 8 buttons or two axis.
-        delete input;
-      }
     }
     udev_device_unref(dev);
   }