diff --git a/.codespellrc b/.codespellrc
index c7019c766..7506fd03d 100644
--- a/.codespellrc
+++ b/.codespellrc
@@ -1,4 +1,4 @@
 [codespell]
-skip = *.dat,typos-config.toml,.git,.venv,./ci,./Dist,./mk,./Tests/ExamplesTest/expected_output,./Tests/ExamplesTest/pcap_examples,./Tests/Packet++Test/PacketExamples,./Tests/Pcap++Test/PcapExamples,./3rdParty,./Examples/PcapSearch/dirent-for-Visual-Studio
+skip = *.dat,typos-config.toml,.git,.venv,venv,./out,./ci,./Dist,./mk,./Tests/ExamplesTest/expected_output,./Tests/ExamplesTest/pcap_examples,./Tests/Packet++Test/PacketExamples,./Tests/Pcap++Test/PcapExamples,./3rdParty,./Examples/PcapSearch/dirent-for-Visual-Studio
 ignore-words = codespell-ignore-list.txt
 count =
diff --git a/Common++/header/DeprecationUtils.h b/Common++/header/DeprecationUtils.h
index 2d600d88d..375bc54c6 100644
--- a/Common++/header/DeprecationUtils.h
+++ b/Common++/header/DeprecationUtils.h
@@ -2,11 +2,27 @@
 
 /// @file
 
+#ifndef PCPP_DEPRECATED_GNU
+#	if defined(__GUNC__) || defined(__clang__)
+#		define PCPP_DEPRECATED_GNU(msg) __attribute__((deprecated(msg)))
+#	else
+#		define PCPP_DEPRECATED_GNU(msg)
+#	endif  // defined(__GUNC__) || defined(__clang__)
+#endif      // !PCPP_DEPRECATED_GNU
+
+#ifndef PCPP_DEPRECATED_MSVC
+#	ifdef _MSC_VER
+#		define PCPP_DEPRECATED_MSVC(msg) __declspec(deprecated(msg))
+#	else
+#		define PCPP_DEPRECATED_MSVC(msg)
+#	endif  // __MSC_VER
+#endif      // !PCPP_DEPRECATED_MSVC
+
 #ifndef PCPP_DEPRECATED
 #	if defined(__GNUC__) || defined(__clang__)
-#		define PCPP_DEPRECATED(msg) __attribute__((deprecated(msg)))
+#		define PCPP_DEPRECATED(msg) PCPP_DEPRECATED_GNU(msg)
 #	elif defined(_MSC_VER)
-#		define PCPP_DEPRECATED(msg) __declspec(deprecated(msg))
+#		define PCPP_DEPRECATED(msg) PCPP_DEPRECATED_MSVC(msg)
 #	else
 #		pragma message("WARNING: DEPRECATED feature is not implemented for this compiler")
 #		define PCPP_DEPRECATED(msg)
diff --git a/Common++/header/PointerVector.h b/Common++/header/PointerVector.h
index 399d7c62d..aecef4aba 100644
--- a/Common++/header/PointerVector.h
+++ b/Common++/header/PointerVector.h
@@ -46,9 +46,12 @@ namespace pcpp
 	/// vector, the element responsibility moves to the vector, meaning the PointerVector will free the object once it's
 	/// removed from the vector This class wraps std::vector and adds the capability of freeing objects once they're
 	/// removed from it
-	template <typename T> class PointerVector
+	template <typename T, typename Deleter = std::default_delete<T>> class PointerVector
 	{
 	public:
+		/// Function object to be called when destroying an element in the vector
+		using deleter_type = Deleter;
+
 		/// Iterator object that is used for iterating all elements in the vector
 		using VectorIterator = typename std::vector<T*>::iterator;
 
@@ -114,6 +117,9 @@ namespace pcpp
 		/// @return A reference to the current object.
 		PointerVector& operator=(PointerVector&& other) noexcept
 		{
+			if (this == &other)
+				return *this;
+
 			// Releases all current elements.
 			clear();
 			// Moves the elements of the other vector.
@@ -153,7 +159,7 @@ namespace pcpp
 			{
 				if (freeElementOnError)
 				{
-					delete element;
+					Deleter()(element);
 				}
 				throw;
 			}
@@ -242,7 +248,7 @@ namespace pcpp
 		/// function call
 		VectorIterator erase(VectorIterator position)
 		{
-			delete (*position);
+			Deleter()(*position);
 			return m_Vector.erase(position);
 		}
 
@@ -326,10 +332,7 @@ namespace pcpp
 			}
 			catch (const std::exception&)
 			{
-				for (auto obj : copyVec)
-				{
-					delete obj;
-				}
+				freeVectorUnsafe(copyVec);
 				throw;
 			}
 
@@ -344,7 +347,7 @@ namespace pcpp
 		{
 			for (auto& obj : origin)
 			{
-				delete obj;
+				Deleter()(obj);
 			}
 		}
 
diff --git a/Examples/ArpSpoofing/main.cpp b/Examples/ArpSpoofing/main.cpp
index 538dd4c7b..b1aef42cf 100644
--- a/Examples/ArpSpoofing/main.cpp
+++ b/Examples/ArpSpoofing/main.cpp
@@ -237,7 +237,7 @@ int main(int argc, char* argv[])
 		EXIT_WITH_ERROR("Gateway address is not valid");
 	}
 
-	pcpp::PcapLiveDevice* pIfaceDevice = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ifaceAddr);
+	pcpp::PcapLiveDevice* pIfaceDevice = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(ifaceAddr);
 
 	// Verifying interface is valid
 	if (pIfaceDevice == nullptr)
diff --git a/Examples/Arping/main.cpp b/Examples/Arping/main.cpp
index 446744b2d..8994ed0dc 100644
--- a/Examples/Arping/main.cpp
+++ b/Examples/Arping/main.cpp
@@ -84,8 +84,7 @@ void printAppVersion()
  */
 void listInterfaces()
 {
-	const std::vector<pcpp::PcapLiveDevice*>& devList =
-	    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
+	const auto& devList = pcpp::PcapLiveDeviceList::getInstance();
 
 	std::cout << std::endl << "Network interfaces:" << std::endl;
 	for (const auto& dev : devList)
@@ -198,7 +197,7 @@ int main(int argc, char* argv[])
 	// Search interface by name or IP
 	if (!ifaceNameOrIP.empty())
 	{
-		dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(ifaceNameOrIP);
+		dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIpOrName(ifaceNameOrIP);
 		if (dev == nullptr)
 			EXIT_WITH_ERROR("Couldn't find interface by provided IP address or name");
 	}
diff --git a/Examples/DNSResolver/main.cpp b/Examples/DNSResolver/main.cpp
index b33792f94..a448f3fc2 100644
--- a/Examples/DNSResolver/main.cpp
+++ b/Examples/DNSResolver/main.cpp
@@ -75,11 +75,8 @@ void printAppVersion()
  */
 void listInterfaces()
 {
-	const std::vector<pcpp::PcapLiveDevice*>& devList =
-	    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
-
 	std::cout << std::endl << "Network interfaces:" << std::endl;
-	for (const auto& dev : devList)
+	for (const auto& dev : pcpp::PcapLiveDeviceList::getInstance())
 	{
 		std::cout << "    -> Name: '" << dev->getName() << "'   IP address: " << dev->getIPv4Address().toString()
 		          << std::endl;
@@ -182,15 +179,14 @@ int main(int argc, char* argv[])
 	// if interface name or IP was provided - find the device accordingly
 	if (interfaceNameOrIPProvided)
 	{
-		dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(interfaceNameOrIP);
+		dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIpOrName(interfaceNameOrIP);
 		if (dev == nullptr)
 			EXIT_WITH_ERROR("Couldn't find interface by provided IP address or name");
 	}
 	// if interface name or IP was not provided - find a device that has a default gateway
 	else
 	{
-		const std::vector<pcpp::PcapLiveDevice*>& devList =
-		    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
+		const auto& devList = pcpp::PcapLiveDeviceList::getInstance();
 
 		auto iter = std::find_if(devList.begin(), devList.end(), [](pcpp::PcapLiveDevice* dev) {
 			return dev->getDefaultGateway() != pcpp::IPv4Address::Zero;
diff --git a/Examples/DnsSpoofing/main.cpp b/Examples/DnsSpoofing/main.cpp
index 8d7ffb012..44ddccd6c 100644
--- a/Examples/DnsSpoofing/main.cpp
+++ b/Examples/DnsSpoofing/main.cpp
@@ -127,8 +127,7 @@ void printAppVersion()
  */
 void listInterfaces()
 {
-	const std::vector<pcpp::PcapLiveDevice*>& devList =
-	    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
+	const auto& devList = pcpp::PcapLiveDeviceList::getInstance();
 
 	std::cout << std::endl << "Network interfaces:" << std::endl;
 	for (const auto& dev : devList)
@@ -450,7 +449,7 @@ int main(int argc, char* argv[])
 		EXIT_WITH_ERROR("Interface name or IP weren't provided. Please use the -i switch or -h for help");
 	}
 
-	dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(interfaceNameOrIP);
+	dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIpOrName(interfaceNameOrIP);
 	if (dev == nullptr)
 		EXIT_WITH_ERROR("Couldn't find interface by provided IP address or name");
 
diff --git a/Examples/HttpAnalyzer/main.cpp b/Examples/HttpAnalyzer/main.cpp
index b321e3cab..c6f818dce 100644
--- a/Examples/HttpAnalyzer/main.cpp
+++ b/Examples/HttpAnalyzer/main.cpp
@@ -123,11 +123,8 @@ void printAppVersion()
  */
 void listInterfaces()
 {
-	const std::vector<pcpp::PcapLiveDevice*>& liveDevices =
-	    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
-
 	std::cout << std::endl << "Network interfaces:" << std::endl;
-	for (const auto& device : liveDevices)
+	for (const auto& device : pcpp::PcapLiveDeviceList::getInstance())
 	{
 		std::cout << "    -> Name: '" << device->getName() << "'   IP address: " << device->getIPv4Address().toString()
 		          << std::endl;
@@ -569,8 +566,7 @@ int main(int argc, char* argv[])
 	}
 	else  // analyze in live traffic mode
 	{
-		pcpp::PcapLiveDevice* dev =
-		    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(interfaceNameOrIP);
+		pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIpOrName(interfaceNameOrIP);
 		if (dev == nullptr)
 			EXIT_WITH_ERROR("Couldn't find interface by provided IP address or name");
 
diff --git a/Examples/IcmpFileTransfer/Common.cpp b/Examples/IcmpFileTransfer/Common.cpp
index b6cc0cd9b..286c6e401 100644
--- a/Examples/IcmpFileTransfer/Common.cpp
+++ b/Examples/IcmpFileTransfer/Common.cpp
@@ -88,8 +88,7 @@ void printAppVersion()
  */
 void listInterfaces()
 {
-	const std::vector<pcpp::PcapLiveDevice*>& devList =
-	    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
+	const auto& devList = pcpp::PcapLiveDeviceList::getInstance();
 
 	std::cout << std::endl << "Network interfaces:" << std::endl;
 	for (const auto& dev : devList)
@@ -174,7 +173,7 @@ void readCommandLineArguments(int argc, char* argv[], const std::string& thisSid
 	}
 	catch (const std::exception&)
 	{
-		pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByName(interfaceNameOrIP);
+		pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByName(interfaceNameOrIP);
 		if (dev == nullptr)
 			EXIT_WITH_ERROR_PRINT_USAGE("Cannot find interface by provided name");
 
diff --git a/Examples/IcmpFileTransfer/IcmpFileTransfer-catcher.cpp b/Examples/IcmpFileTransfer/IcmpFileTransfer-catcher.cpp
index 470b66660..5d5f8f576 100644
--- a/Examples/IcmpFileTransfer/IcmpFileTransfer-catcher.cpp
+++ b/Examples/IcmpFileTransfer/IcmpFileTransfer-catcher.cpp
@@ -203,7 +203,7 @@ static bool getFileContent(pcpp::RawPacket* rawPacket, pcpp::PcapLiveDevice* dev
 void receiveFile(pcpp::IPv4Address pitcherIP, pcpp::IPv4Address catcherIP)
 {
 	// identify the interface to listen and send packets to
-	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(catcherIP);
+	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(catcherIP);
 	if (dev == nullptr)
 		EXIT_WITH_ERROR("Cannot find network interface with IP '" << catcherIP << "'");
 
@@ -416,7 +416,7 @@ static bool sendContent(pcpp::RawPacket* rawPacket, pcpp::PcapLiveDevice* dev, v
 void sendFile(const std::string& filePath, pcpp::IPv4Address pitcherIP, pcpp::IPv4Address catcherIP, size_t blockSize)
 {
 	// identify the interface to listen and send packets to
-	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(catcherIP);
+	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(catcherIP);
 	if (dev == nullptr)
 		EXIT_WITH_ERROR("Cannot find network interface with IP '" << catcherIP << "'");
 
diff --git a/Examples/IcmpFileTransfer/IcmpFileTransfer-pitcher.cpp b/Examples/IcmpFileTransfer/IcmpFileTransfer-pitcher.cpp
index 59019d074..6825bd703 100644
--- a/Examples/IcmpFileTransfer/IcmpFileTransfer-pitcher.cpp
+++ b/Examples/IcmpFileTransfer/IcmpFileTransfer-pitcher.cpp
@@ -221,7 +221,7 @@ static void getFileContent(pcpp::RawPacket* rawPacket, pcpp::PcapLiveDevice* dev
 void receiveFile(pcpp::IPv4Address pitcherIP, pcpp::IPv4Address catcherIP, int packetPerSec)
 {
 	// identify the interface to listen and send packets to
-	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(pitcherIP);
+	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(pitcherIP);
 	if (dev == nullptr)
 		EXIT_WITH_ERROR("Cannot find network interface with IP '" << pitcherIP << "'");
 
@@ -404,7 +404,7 @@ void sendFile(const std::string& filePath, pcpp::IPv4Address pitcherIP, pcpp::IP
               int packetPerSec)
 {
 	// identify the interface to listen and send packets to
-	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(pitcherIP);
+	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(pitcherIP);
 	if (dev == nullptr)
 		EXIT_WITH_ERROR("Cannot find network interface with IP '" << pitcherIP << "'");
 
diff --git a/Examples/PfRingExample-FilterTraffic/main.cpp b/Examples/PfRingExample-FilterTraffic/main.cpp
index f070fceb6..7cbb1ff0e 100644
--- a/Examples/PfRingExample-FilterTraffic/main.cpp
+++ b/Examples/PfRingExample-FilterTraffic/main.cpp
@@ -141,7 +141,7 @@ void listPfRingDevices()
 	// suppress errors as there may be devices (like lo) that their MAC address can't be read, etc.
 	pcpp::Logger::getInstance().suppressLogs();
 
-	const std::vector<pcpp::PfRingDevice*>& devList = pcpp::PfRingDeviceList::getInstance().getPfRingDevicesList();
+	const auto& devList = pcpp::PfRingDeviceList::getInstance();
 	for (const auto& dev : devList)
 	{
 		std::ostringstream interfaceIndex;
@@ -277,7 +277,7 @@ int main(int argc, char* argv[])
 		case 'n':
 		{
 			std::string ifaceName = std::string(optarg);
-			dev = pcpp::PfRingDeviceList::getInstance().getPfRingDeviceByName(ifaceName);
+			dev = pcpp::PfRingDeviceList::getInstance().getDeviceByName(ifaceName);
 			if (dev == nullptr)
 				EXIT_WITH_ERROR("Could not find PF_RING device '" << ifaceName << "'");
 			break;
@@ -285,7 +285,7 @@ int main(int argc, char* argv[])
 		case 's':
 		{
 			std::string sendPacketsToIfaceName = std::string(optarg);
-			sendPacketsToIface = pcpp::PfRingDeviceList::getInstance().getPfRingDeviceByName(sendPacketsToIfaceName);
+			sendPacketsToIface = pcpp::PfRingDeviceList::getInstance().getDeviceByName(sendPacketsToIfaceName);
 			if (sendPacketsToIface == nullptr)
 				EXIT_WITH_ERROR("Could not find PF_RING device '" << sendPacketsToIfaceName << "'");
 
diff --git a/Examples/SSLAnalyzer/main.cpp b/Examples/SSLAnalyzer/main.cpp
index bf644e748..f5e791bbe 100644
--- a/Examples/SSLAnalyzer/main.cpp
+++ b/Examples/SSLAnalyzer/main.cpp
@@ -119,8 +119,7 @@ void printAppVersion()
  */
 void listInterfaces()
 {
-	const std::vector<pcpp::PcapLiveDevice*>& devList =
-	    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
+	const auto& devList = pcpp::PcapLiveDeviceList::getInstance();
 
 	std::cout << std::endl << "Network interfaces:" << std::endl;
 	for (const auto& dev : devList)
@@ -531,8 +530,7 @@ int main(int argc, char* argv[])
 	else  // analyze in live traffic mode
 	{
 		// extract pcap live device by interface name or IP address
-		pcpp::PcapLiveDevice* dev =
-		    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(interfaceNameOrIP);
+		pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIpOrName(interfaceNameOrIP);
 		if (dev == nullptr)
 			EXIT_WITH_ERROR("Couldn't find interface by provided IP address or name");
 
diff --git a/Examples/TLSFingerprinting/main.cpp b/Examples/TLSFingerprinting/main.cpp
index 3c25dea9c..18ac62c8b 100644
--- a/Examples/TLSFingerprinting/main.cpp
+++ b/Examples/TLSFingerprinting/main.cpp
@@ -141,8 +141,7 @@ void printAppVersion()
  */
 void listInterfaces()
 {
-	const std::vector<pcpp::PcapLiveDevice*>& devList =
-	    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
+	const auto& devList = pcpp::PcapLiveDeviceList::getInstance();
 
 	std::cout << std::endl << "Network interfaces:" << std::endl;
 	for (const auto& dev : devList)
@@ -462,7 +461,7 @@ void doTlsFingerprintingOnLiveTraffic(const std::string& interfaceNameOrIP, std:
                                       const std::string& separator, bool chFP, bool shFP, const std::string& bpfFilter)
 {
 	// extract pcap live device by interface name or IP address
-	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(interfaceNameOrIP);
+	pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIpOrName(interfaceNameOrIP);
 	if (dev == nullptr)
 		EXIT_WITH_ERROR("Couldn't find interface by given IP address or name");
 
diff --git a/Examples/TcpReassembly/main.cpp b/Examples/TcpReassembly/main.cpp
index 5b6b8a520..eb422565a 100644
--- a/Examples/TcpReassembly/main.cpp
+++ b/Examples/TcpReassembly/main.cpp
@@ -329,11 +329,9 @@ void printAppVersion()
  */
 void listInterfaces()
 {
-	auto const& devList = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
-
 	std::cout << std::endl << "Network interfaces:" << std::endl;
 
-	for (auto dev : devList)
+	for (auto dev : pcpp::PcapLiveDeviceList::getInstance())
 	{
 		std::cout << "    -> Name: '" << dev->getName() << "'   IP address: " << dev->getIPv4Address().toString()
 		          << std::endl;
@@ -689,8 +687,7 @@ int main(int argc, char* argv[])
 	else  // analyze in live traffic mode
 	{
 		// extract pcap live device by interface name or IP address
-		pcpp::PcapLiveDevice* dev =
-		    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(interfaceNameOrIP);
+		pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIpOrName(interfaceNameOrIP);
 		if (dev == nullptr)
 			EXIT_WITH_ERROR("Couldn't find interface by provided IP address or name");
 
diff --git a/Examples/XdpExample-FilterTraffic/main.cpp b/Examples/XdpExample-FilterTraffic/main.cpp
index f08b180c4..7fa7edc56 100644
--- a/Examples/XdpExample-FilterTraffic/main.cpp
+++ b/Examples/XdpExample-FilterTraffic/main.cpp
@@ -356,7 +356,7 @@ void printAppVersion()
 void listInterfaces()
 {
 	std::cout << std::endl << "Network interfaces:" << std::endl;
-	for (const auto& device : pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList())
+	for (const auto& device : pcpp::PcapLiveDeviceList::getInstance())
 	{
 		if (device->getIPv4Address() != pcpp::IPv4Address::Zero)
 		{
diff --git a/Pcap++/CMakeLists.txt b/Pcap++/CMakeLists.txt
index 7eb772b14..7687e4c60 100644
--- a/Pcap++/CMakeLists.txt
+++ b/Pcap++/CMakeLists.txt
@@ -28,6 +28,7 @@ add_library(
 set(
   public_headers
   header/Device.h
+  header/DeviceListBase.h
   header/NetworkUtils.h
   header/PcapDevice.h
   header/PcapFileDevice.h
diff --git a/Pcap++/header/DeviceListBase.h b/Pcap++/header/DeviceListBase.h
new file mode 100644
index 000000000..9d1933fe3
--- /dev/null
+++ b/Pcap++/header/DeviceListBase.h
@@ -0,0 +1,175 @@
+#pragma once
+
+/// @file
+
+#include "PointerVector.h"
+
+namespace pcpp
+{
+	namespace internal
+	{
+		/**
+		 * @class DeviceListBase
+		 * A base class for all device lists in PcapPlusPlus. This class is used to store a list of devices and provide
+		 * access to them
+		 */
+		template <class DeviceType, class DeviceDeleter = std::default_delete<DeviceType>> class DeviceListBase
+		{
+		protected:
+			PointerVector<DeviceType, DeviceDeleter> m_DeviceList;
+
+			DeviceListBase() = default;
+			explicit DeviceListBase(PointerVector<DeviceType, DeviceDeleter> devices) : m_DeviceList(std::move(devices))
+			{}
+			DeviceListBase(DeviceListBase const&) = default;
+			DeviceListBase(DeviceListBase&&) = default;
+			// Protected destructor to disallow deletion of derived class through a base class pointer
+			~DeviceListBase() = default;
+
+			DeviceListBase& operator=(DeviceListBase const&) = default;
+			DeviceListBase& operator=(DeviceListBase&&) = default;
+
+		public:
+			using value_type = DeviceType*;
+			using size_type = std::size_t;
+			using difference_type = std::ptrdiff_t;
+
+			/**
+			 * Iterator object that can be used to iterate all devices.
+			 */
+			using iterator = typename PointerVector<DeviceType>::VectorIterator;
+
+			/**
+			 * Const iterator object that can be used to iterate all devices.
+			 */
+			using const_iterator = typename PointerVector<DeviceType>::ConstVectorIterator;
+
+			/**
+			 * @brief Returns a pointer to the device at the specified position in the container.
+			 * @param pos The position of the device.
+			 * @return A pointer to the specified device.
+			 */
+			DeviceType* at(size_type pos)
+			{
+				return m_DeviceList.at(pos);
+			}
+
+			/**
+			 * @brief Returns a pointer to the device at the specified position in the container.
+			 * @param pos The position of the device.
+			 * @return A pointer to the specified device.
+			 */
+			DeviceType const* at(size_type pos) const
+			{
+				return m_DeviceList.at(pos);
+			}
+
+			/**
+			 * @brief Returns a pointer to first device.
+			 * @return A pointer to the specified device.
+			 */
+			DeviceType* front()
+			{
+				return m_DeviceList.front();
+			}
+			/**
+			 * @brief Returns a pointer to first device.
+			 * @return A pointer to the specified device.
+			 */
+			DeviceType const* front() const
+			{
+				return m_DeviceList.front();
+			}
+
+			/**
+			 * @brief Returns a pointer to last device.
+			 * @return A pointer to the specified device.
+			 */
+			DeviceType* back()
+			{
+				return m_DeviceList.back();
+			}
+
+			/**
+			 * @brief Returns a pointer to last device.
+			 * @return A pointer to the specified device.
+			 */
+			DeviceType const* back() const
+			{
+				return m_DeviceList.back();
+			}
+
+			/**
+			 * @brief Returns an iterator to the first device.
+			 * @return An iterator to the specified device.
+			 */
+			iterator begin()
+			{
+				return m_DeviceList.begin();
+			}
+
+			/**
+			 * @brief Returns an iterator to the first device.
+			 * @return An iterator to the specified device.
+			 */
+			const_iterator begin() const
+			{
+				return cbegin();
+			}
+
+			/**
+			 * @brief Returns an iterator to the first device.
+			 * @return An iterator to the specified device.
+			 */
+			const_iterator cbegin() const
+			{
+				return m_DeviceList.begin();
+			}
+
+			/**
+			 * @brief Returns an iterator past the last device.
+			 * @return An iterator past the last device.
+			 */
+			iterator end()
+			{
+				return m_DeviceList.end();
+			}
+
+			/**
+			 * @brief Returns an iterator past the last device.
+			 * @return An iterator past the last device.
+			 */
+			const_iterator end() const
+			{
+				return cend();
+			}
+
+			/**
+			 * @brief Returns an iterator past the last device.
+			 * @return An iterator past the last device.
+			 */
+			const_iterator cend() const
+			{
+				return m_DeviceList.end();
+			}
+
+			/**
+			 * @brief Checks if the container is empty.
+			 * @return True if the container is empty, false otherwise.
+			 */
+			bool empty() const
+			{
+				return m_DeviceList.size() == 0;
+			}
+
+			/**
+			 * @brief Returns the number of devices.
+			 * @return The number of devices in the container.
+			 */
+			size_type size() const
+			{
+				return m_DeviceList.size();
+			}
+		};
+	}  // namespace internal
+}  // namespace pcpp
diff --git a/Pcap++/header/DpdkDeviceList.h b/Pcap++/header/DpdkDeviceList.h
index 2d91f91ef..e2316c7a9 100644
--- a/Pcap++/header/DpdkDeviceList.h
+++ b/Pcap++/header/DpdkDeviceList.h
@@ -4,6 +4,7 @@
 
 #include "SystemUtils.h"
 #include "DpdkDevice.h"
+#include "DeviceListBase.h"
 #include "Logger.h"
 #include <vector>
 
@@ -54,7 +55,7 @@ namespace pcpp
 	///      once in every application at its startup process
 	///    - it contains the list of DpdkDevice instances and enables access to them
 	///    - it has methods to start and stop worker threads. See more details in startDpdkWorkerThreads()
-	class DpdkDeviceList
+	class DpdkDeviceList : public internal::DeviceListBase<DpdkDevice>
 	{
 		friend class KniDeviceList;
 
@@ -64,7 +65,7 @@ namespace pcpp
 		static uint32_t m_MBufPoolSizePerDevice;
 		static uint16_t m_MBufDataSize;
 		static CoreMask m_CoreMask;
-		std::vector<DpdkDevice*> m_DpdkDeviceList;
+		std::vector<DpdkDevice*> m_DpdkDeviceListView;
 		std::vector<DpdkWorkerThread*> m_WorkerThreads;
 
 		DpdkDeviceList();
@@ -79,7 +80,7 @@ namespace pcpp
 		static int dpdkWorkerThreadStart(void* ptr);
 
 	public:
-		~DpdkDeviceList();
+		~DpdkDeviceList() = default;
 
 		/// As DpdkDeviceList is a singleton, this is the static getter to retrieve its instance. Note that if the
 		/// static method initDpdk() was not called or returned false this instance won't be initialized and DpdkDevices
@@ -137,9 +138,11 @@ namespace pcpp
 		DpdkDevice* getDeviceByPciAddress(const std::string& pciAddr) const;
 
 		/// @return A vector of all DpdkDevice instances
+		/// @deprecated This method has been deprecated in favor of direct accessor API.
+		PCPP_DEPRECATED("Deprecated in favor of direct accessor API")
 		const std::vector<DpdkDevice*>& getDpdkDeviceList() const
 		{
-			return m_DpdkDeviceList;
+			return m_DpdkDeviceListView;
 		}
 
 		/// @return DPDK master core which is the core that initializes the application
diff --git a/Pcap++/header/KniDevice.h b/Pcap++/header/KniDevice.h
index 64d3099e1..d0c2b1ee4 100644
--- a/Pcap++/header/KniDevice.h
+++ b/Pcap++/header/KniDevice.h
@@ -85,6 +85,11 @@ namespace pcpp
 	class KniDevice;
 	class KniDeviceList;
 
+	namespace internal
+	{
+		class KniDeviceDeleter;
+	}
+
 	/// Defines the signature callback used by capturing API on KNI device
 	typedef bool (*OnKniPacketArriveCallback)(MBufRawPacket* packets, uint32_t numOfPackets, KniDevice* device,
 	                                          void* userCookie);
@@ -115,6 +120,7 @@ namespace pcpp
 	class KniDevice : public IDevice
 	{
 		friend class KniDeviceList;
+		friend struct internal::KniDeviceDeleter;
 		friend class MBufRawPacket;
 
 	public:
@@ -237,7 +243,7 @@ namespace pcpp
 		/// This class is not copyable
 		KniDevice& operator=(const KniDevice&);
 		/// All instances of this class MUST be destroyed by KniDeviceList class
-		~KniDevice();
+		~KniDevice() override;
 
 	public:
 		/// Indicates whether the KNI device was initialized successfully
@@ -518,11 +524,11 @@ namespace pcpp
 		/// Takes appropriate actions for opening KNI device.
 		/// @return true if the device was opened successfully, false if device is already opened,
 		/// or KNI device configuration and startup failed
-		bool open();
+		bool open() override;
 		/// @brief Close the KNI device.
 		/// When device is closed it's not possible to work with it.
 		/// Stops asynchronous packet capture if it is running.
-		void close();
+		void close() override;
 
 	private:
 		struct rte_kni* m_Device;
diff --git a/Pcap++/header/KniDeviceList.h b/Pcap++/header/KniDeviceList.h
index bfd2386fd..b1589e4c4 100644
--- a/Pcap++/header/KniDeviceList.h
+++ b/Pcap++/header/KniDeviceList.h
@@ -2,20 +2,33 @@
 
 // GCOVR_EXCL_START
 
-#include <vector>
-
 #include "KniDevice.h"
 #include "DpdkDeviceList.h"
+#include "DeviceListBase.h"
 
 /// @namespace pcpp
 /// @brief The main namespace for the PcapPlusPlus lib
 namespace pcpp
 {
+
+	namespace internal
+	{
+		/// @class KniDeviceDeleter
+		/// Specialized deleter for KniDevice. Do not use outside of KniDeviceList.
+		struct KniDeviceDeleter
+		{
+			void operator()(KniDevice* kniDevice)
+			{
+				delete kniDevice;
+			}
+		};
+	}  // namespace internal
+
 	/// @class KniDeviceList
 	/// A singleton class that encapsulates DPDK KNI module initialization
 	/// and holds the list of KniDevice instances.
 	/// As it's a singleton, it has only one active instance doesn't have a public c'tor.
-	class KniDeviceList
+	class KniDeviceList : public internal::DeviceListBase<KniDevice, internal::KniDeviceDeleter>
 	{
 		KniDeviceList();
 
@@ -97,7 +110,6 @@ namespace pcpp
 		static bool isCallbackSupported(const KniCallbackType cbType);
 
 	private:
-		std::vector<KniDevice*> m_Devices;
 		bool m_Initialized;
 		int m_KniUniqueId;
 	};
diff --git a/Pcap++/header/PcapLiveDeviceList.h b/Pcap++/header/PcapLiveDeviceList.h
index bb4a842d6..b6de6b01b 100644
--- a/Pcap++/header/PcapLiveDeviceList.h
+++ b/Pcap++/header/PcapLiveDeviceList.h
@@ -1,9 +1,11 @@
 #pragma once
 
-#include "IpAddress.h"
-#include "PcapLiveDevice.h"
 #include <vector>
 #include <memory>
+#include "IpAddress.h"
+#include "PcapLiveDevice.h"
+#include "DeviceListBase.h"
+#include "DeprecationUtils.h"
 
 /// @file
 
@@ -16,10 +18,11 @@ namespace pcpp
 	/// (on Windows) instances. All live devices are initialized on startup and wrap the network interfaces installed on
 	/// the machine. This class enables access to them through their IP addresses or get a vector of all of them so the
 	/// user can search them in some other way
-	class PcapLiveDeviceList
+	class PcapLiveDeviceList : public internal::DeviceListBase<PcapLiveDevice>
 	{
 	private:
-		std::vector<std::unique_ptr<PcapLiveDevice>> m_LiveDeviceList;
+		using Base = internal::DeviceListBase<PcapLiveDevice>;
+
 		// Vector of raw device pointers to keep the signature of getPcapLiveDevicesList, as it returns a reference.
 		std::vector<PcapLiveDevice*> m_LiveDeviceListView;
 
@@ -28,7 +31,7 @@ namespace pcpp
 		// private c'tor
 		PcapLiveDeviceList();
 
-		static std::vector<std::unique_ptr<PcapLiveDevice>> fetchAllLocalDevices();
+		static PointerVector<PcapLiveDevice> fetchAllLocalDevices();
 		static std::vector<IPv4Address> fetchDnsServers();
 
 	public:
@@ -36,6 +39,7 @@ namespace pcpp
 		PcapLiveDeviceList(PcapLiveDeviceList&&) noexcept = delete;
 		PcapLiveDeviceList& operator=(const PcapLiveDeviceList&) = delete;
 		PcapLiveDeviceList& operator=(PcapLiveDeviceList&&) noexcept = delete;
+		~PcapLiveDeviceList() = default;
 
 		/// The access method to the singleton
 		/// @return The singleton instance of this class
@@ -46,6 +50,8 @@ namespace pcpp
 		}
 
 		/// @return A vector containing pointers to all live devices currently installed on the machine
+		/// @deprecated This method has been deprecated in favor of direct accessor API.
+		PCPP_DEPRECATED("Deprecated in favor of direct accessor API")
 		const std::vector<PcapLiveDevice*>& getPcapLiveDevicesList() const
 		{
 			return m_LiveDeviceListView;
@@ -54,33 +60,94 @@ namespace pcpp
 		/// Get a pointer to the live device by its IP address. IP address can be both IPv4 or IPv6
 		/// @param[in] ipAddr The IP address defined for the device
 		/// @return A pointer to the live device if this IP address exists. nullptr otherwise
-		PcapLiveDevice* getPcapLiveDeviceByIp(const IPAddress& ipAddr) const;
+		PcapLiveDevice* getDeviceByIp(const IPAddress& ipAddr) const;
+
+		/// Get a pointer to the live device by its IP address. IP address can be both IPv4 or IPv6
+		/// @param[in] ipAddr The IP address defined for the device
+		/// @return A pointer to the live device if this IP address exists. nullptr otherwise
+		/// @deprecated This method has been deprecated in favor of getDeviceByIp(...).
+		PCPP_DEPRECATED("Please use getDeviceByIp(...) instead.")
+		PcapLiveDevice* getPcapLiveDeviceByIp(const IPAddress& ipAddr) const
+		{
+			return getDeviceByIp(ipAddr);
+		}
 
 		/// Get a pointer to the live device by its IPv4 address
 		/// @param[in] ipAddr The IPv4 address defined for the device
 		/// @return A pointer to the live device if this IPv4 address exists. nullptr otherwise
-		PcapLiveDevice* getPcapLiveDeviceByIp(const IPv4Address& ipAddr) const;
+		PcapLiveDevice* getDeviceByIp(const IPv4Address& ipAddr) const;
+
+		/// Get a pointer to the live device by its IPv4 address
+		/// @param[in] ipAddr The IPv4 address defined for the device
+		/// @return A pointer to the live device if this IPv4 address exists. nullptr otherwise
+		/// @deprecated This method has been deprecated in favor of getDeviceByIp(...).
+		PCPP_DEPRECATED("Please use getDeviceByIp(...) instead.")
+		PcapLiveDevice* getPcapLiveDeviceByIp(const IPv4Address& ipAddr) const
+		{
+			return getDeviceByIp(ipAddr);
+		}
+
+		/// Get a pointer to the live device by its IPv6 address
+		/// @param[in] ip6Addr The IPv6 address defined for the device
+		/// @return A pointer to the live device if this IPv6 address exists. nullptr otherwise
+		PcapLiveDevice* getDeviceByIp(const IPv6Address& ip6Addr) const;
 
 		/// Get a pointer to the live device by its IPv6 address
 		/// @param[in] ip6Addr The IPv6 address defined for the device
 		/// @return A pointer to the live device if this IPv6 address exists. nullptr otherwise
-		PcapLiveDevice* getPcapLiveDeviceByIp(const IPv6Address& ip6Addr) const;
+		/// @deprecated This method has been deprecated in favor of getDeviceByIp(...).
+		PCPP_DEPRECATED("Please use getDeviceByIp(...) instead.")
+		PcapLiveDevice* getPcapLiveDeviceByIp(const IPv6Address& ip6Addr) const
+		{
+			return getDeviceByIp(ip6Addr);
+		}
 
 		/// Get a pointer to the live device by its IP address represented as string. IP address can be both IPv4 or
 		/// IPv6
 		/// @param[in] ipAddrAsString The IP address defined for the device as string
 		/// @return A pointer to the live device if this IP address is valid and exists. nullptr otherwise
-		PcapLiveDevice* getPcapLiveDeviceByIp(const std::string& ipAddrAsString) const;
+		PcapLiveDevice* getDeviceByIp(const std::string& ipAddrAsString) const;
+
+		/// Get a pointer to the live device by its IP address represented as string. IP address can be both IPv4 or
+		/// IPv6
+		/// @param[in] ipAddrAsString The IP address defined for the device as string
+		/// @return A pointer to the live device if this IP address is valid and exists. nullptr otherwise
+		/// @deprecated This method has been deprecated in favor of getDeviceByIp(...).
+		PCPP_DEPRECATED("Please use getDeviceByIp(...) instead.")
+		PcapLiveDevice* getPcapLiveDeviceByIp(const std::string& ipAddrAsString) const
+		{
+			return getDeviceByIp(ipAddrAsString);
+		}
 
 		/// Get a pointer to the live device by its name
 		/// @param[in] name The name of the interface (e.g eth0)
 		/// @return A pointer to the live device if this name exists. nullptr otherwise
-		PcapLiveDevice* getPcapLiveDeviceByName(const std::string& name) const;
+		PcapLiveDevice* getDeviceByName(const std::string& name) const;
+
+		/// Get a pointer to the live device by its name
+		/// @param[in] name The name of the interface (e.g eth0)
+		/// @return A pointer to the live device if this name exists. nullptr otherwise
+		/// @deprecated This method has been deprecated in favor of getDeviceByName(...).
+		PCPP_DEPRECATED("Please use getDeviceByName(...) instead.")
+		PcapLiveDevice* getPcapLiveDeviceByName(const std::string& name) const
+		{
+			return getDeviceByName(name);
+		}
+
+		/// Get a pointer to the live device by its IP address or name
+		/// @param[in] ipOrName An IP address or name of the interface
+		/// @return A pointer to the live device if exists, nullptr otherwise
+		PcapLiveDevice* getDeviceByIpOrName(const std::string& ipOrName) const;
 
 		/// Get a pointer to the live device by its IP address or name
 		/// @param[in] ipOrName An IP address or name of the interface
 		/// @return A pointer to the live device if exists, nullptr otherwise
-		PcapLiveDevice* getPcapLiveDeviceByIpOrName(const std::string& ipOrName) const;
+		/// @deprecated This method has been deprecated in favor of getDeviceByIpOrName(...).
+		PCPP_DEPRECATED("Please use getDeviceByIp(...) instead.")
+		PcapLiveDevice* getPcapLiveDeviceByIpOrName(const std::string& ipOrName) const
+		{
+			return getDeviceByIpOrName(ipOrName);
+		}
 
 		/// @return A list of all DNS servers defined for this machine. If this list is empty it means no DNS servers
 		/// were defined or they couldn't be extracted from some reason
diff --git a/Pcap++/header/PcapRemoteDeviceList.h b/Pcap++/header/PcapRemoteDeviceList.h
index b8a07bbf5..7fe8d4bc4 100644
--- a/Pcap++/header/PcapRemoteDeviceList.h
+++ b/Pcap++/header/PcapRemoteDeviceList.h
@@ -2,6 +2,7 @@
 
 #include <memory>
 #include "IpAddress.h"
+#include "DeviceListBase.h"
 #include "PcapRemoteDevice.h"
 #include "DeprecationUtils.h"
 
@@ -21,10 +22,11 @@ namespace pcpp
 	/// interface or by iterating the PcapRemoteDevice instances (through the
 	/// PcapRemoteDeviceList#RemoteDeviceListIterator iterator)<BR> Since Remote Capture is supported in WinPcap and
 	/// Npcap only, this class is available in Windows only
-	class PcapRemoteDeviceList
+	class PcapRemoteDeviceList : public internal::DeviceListBase<PcapRemoteDevice>
 	{
 	private:
-		std::vector<PcapRemoteDevice*> m_RemoteDeviceList;
+		using Base = internal::DeviceListBase<PcapRemoteDevice>;
+
 		IPAddress m_RemoteMachineIpAddress;
 		uint16_t m_RemoteMachinePort;
 		std::shared_ptr<PcapRemoteAuthentication> m_RemoteAuthentication;
@@ -32,21 +34,33 @@ namespace pcpp
 		// private c'tor. User should create the list via static methods PcapRemoteDeviceList::createRemoteDeviceList()
 		PcapRemoteDeviceList(const IPAddress& ipAddress, uint16_t port,
 		                     std::shared_ptr<PcapRemoteAuthentication> remoteAuth,
-		                     std::vector<PcapRemoteDevice*> deviceList);
+		                     PointerVector<PcapRemoteDevice> deviceList);
 
 	public:
+#define PCPP_REMOTE_LIST_ITERATOR_MSG "Please use the 'iterator' alias instead of 'RemoteDeviceListIterator'."
+		// Preprocessor hacks because GNU/Clang and MSVC expect their compiler specific attributes differently for
+		// aliases. I wish the minimum supported standard was Cpp14 :'(
+
 		/// Iterator object that can be used for iterating all PcapRemoteDevice in list
-		using RemoteDeviceListIterator = typename std::vector<PcapRemoteDevice*>::iterator;
+		/// @deprecated Please use the 'iterator' alias instead of 'RemoteDeviceListIterator'.
+		using RemoteDeviceListIterator PCPP_DEPRECATED_GNU(PCPP_REMOTE_LIST_ITERATOR_MSG) =
+		    PCPP_DEPRECATED_MSVC(PCPP_REMOTE_LIST_ITERATOR_MSG) iterator;
+#undef PCPP_REMOTE_LIST_ITERATOR_MSG
+
+#define PCPP_REMOTE_LIST_ITERATOR_MSG                                                                                  \
+	"Please use the 'const_iterator' alias instead of 'ConstRemoteDeviceListIterator'."
 
 		/// Const iterator object that can be used for iterating all PcapRemoteDevice in a constant list
-		using ConstRemoteDeviceListIterator = typename std::vector<PcapRemoteDevice*>::const_iterator;
+		/// @deprecated Please use the 'const_iterator' alias instead of 'ConstRemoteDeviceListIterator'.
+		using ConstRemoteDeviceListIterator PCPP_DEPRECATED_GNU(PCPP_REMOTE_LIST_ITERATOR_MSG) =
+		    PCPP_DEPRECATED_MSVC(PCPP_REMOTE_LIST_ITERATOR_MSG) const_iterator;
+#undef PCPP_REMOTE_LIST_ITERATOR_MSG
 
 		PcapRemoteDeviceList(const PcapRemoteDeviceList&) = delete;
 		PcapRemoteDeviceList(PcapRemoteDeviceList&&) noexcept = delete;
 		PcapRemoteDeviceList& operator=(const PcapRemoteDeviceList&) = delete;
 		PcapRemoteDeviceList& operator=(PcapRemoteDeviceList&&) noexcept = delete;
-
-		~PcapRemoteDeviceList();
+		~PcapRemoteDeviceList() = default;
 
 		/// A static method for creating a PcapRemoteDeviceList instance for a certain remote machine. This methods
 		/// creates the instance, and also creates a list of PcapRemoteDevice instances stored in it, one for each
@@ -140,45 +154,61 @@ namespace pcpp
 		/// Search a PcapRemoteDevice in the list by its IPv4 address
 		/// @param[in] ip4Addr The IPv4 address
 		/// @return The PcapRemoteDevice if found, nullptr otherwise
-		PcapRemoteDevice* getRemoteDeviceByIP(const IPv4Address& ip4Addr) const;
+		PcapRemoteDevice* getDeviceByIp(const IPv4Address& ip4Addr) const;
+
+		/// Search a PcapRemoteDevice in the list by its IPv4 address
+		/// @param[in] ip4Addr The IPv4 address
+		/// @return The PcapRemoteDevice if found, NULL otherwise
+		/// @deprecated This method has been deprecated in favor of getDeviceByIp(...).
+		PCPP_DEPRECATED("Please use getDeviceByIp(...) instead.")
+		PcapRemoteDevice* getRemoteDeviceByIP(const IPv4Address& ip4Addr) const
+		{
+			return getDeviceByIp(ip4Addr);
+		}
 
 		/// Search a PcapRemoteDevice in the list by its IPv6 address
 		/// @param[in] ip6Addr The IPv6 address
 		/// @return The PcapRemoteDevice if found, nullptr otherwise
-		PcapRemoteDevice* getRemoteDeviceByIP(const IPv6Address& ip6Addr) const;
+		PcapRemoteDevice* getDeviceByIp(const IPv6Address& ip6Addr) const;
+
+		/// Search a PcapRemoteDevice in the list by its IPv6 address
+		/// @param[in] ip6Addr The IPv6 address
+		/// @return The PcapRemoteDevice if found, nullptr otherwise
+		/// @deprecated This method has been deprecated in favor of getDeviceByIp(...).
+		PCPP_DEPRECATED("Please use getDeviceByIp(...) instead.")
+		PcapRemoteDevice* getRemoteDeviceByIP(const IPv6Address& ip6Addr) const
+		{
+			return getDeviceByIp(ip6Addr);
+		}
 
 		/// Search a PcapRemoteDevice in the list by its IP address (IPv4 or IPv6)
 		/// @param[in] ipAddr The IP address
 		/// @return The PcapRemoteDevice if found, nullptr otherwise
-		PcapRemoteDevice* getRemoteDeviceByIP(const IPAddress& ipAddr) const;
+		PcapRemoteDevice* getDeviceByIp(const IPAddress& ipAddr) const;
 
-		/// Search a PcapRemoteDevice in the list by its IP address
-		/// @param[in] ipAddrAsString The IP address in string format
+		/// Search a PcapRemoteDevice in the list by its IP address (IPv4 or IPv6)
+		/// @param[in] ipAddr The IP address
 		/// @return The PcapRemoteDevice if found, nullptr otherwise
-		PcapRemoteDevice* getRemoteDeviceByIP(const std::string& ipAddrAsString) const;
-
-		/// @return An iterator object pointing to the first PcapRemoteDevice in list
-		RemoteDeviceListIterator begin()
-		{
-			return m_RemoteDeviceList.begin();
-		}
-
-		/// @return A const iterator object pointing to the first PcapRemoteDevice in list
-		ConstRemoteDeviceListIterator begin() const
+		/// @deprecated This method has been deprecated in favor of getDeviceByIp(...).
+		PCPP_DEPRECATED("Please use getDeviceByIp(...) instead.")
+		PcapRemoteDevice* getRemoteDeviceByIP(const IPAddress& ipAddr) const
 		{
-			return m_RemoteDeviceList.begin();
+			return getDeviceByIp(ipAddr);
 		}
 
-		/// @return An iterator object pointing to the last PcapRemoteDevice in list
-		RemoteDeviceListIterator end()
-		{
-			return m_RemoteDeviceList.end();
-		}
+		/// Search a PcapRemoteDevice in the list by its IP address
+		/// @param[in] ipAddrAsString The IP address in string format
+		/// @return The PcapRemoteDevice if found, NULL otherwise
+		PcapRemoteDevice* getDeviceByIp(const std::string& ipAddrAsString) const;
 
-		/// @return A const iterator object pointing to the last PcapRemoteDevice in list
-		ConstRemoteDeviceListIterator end() const
+		/// Search a PcapRemoteDevice in the list by its IP address
+		/// @param[in] ipAddrAsString The IP address in string format
+		/// @return The PcapRemoteDevice if found, NULL otherwise
+		/// @deprecated This method has been deprecated in favor of getDeviceByIp(...).
+		PCPP_DEPRECATED("Please use getDeviceByIp(...) instead.")
+		PcapRemoteDevice* getRemoteDeviceByIP(const std::string& ipAddrAsString) const
 		{
-			return m_RemoteDeviceList.end();
+			return getDeviceByIp(ipAddrAsString);
 		}
 	};
 }  // namespace pcpp
diff --git a/Pcap++/header/PfRingDeviceList.h b/Pcap++/header/PfRingDeviceList.h
index 6e364c59e..f9f6d8fb0 100644
--- a/Pcap++/header/PfRingDeviceList.h
+++ b/Pcap++/header/PfRingDeviceList.h
@@ -3,6 +3,8 @@
 // GCOVR_EXCL_START
 
 #include "PfRingDevice.h"
+#include "DeviceListBase.h"
+#include "DeprecationUtils.h"
 
 /// @file
 
@@ -13,10 +15,11 @@ namespace pcpp
 	/// @class PfRingDeviceList
 	/// A singleton class that holds all available PF_RING devices. Through this class the user can iterate all PF_RING
 	/// devices or find a specific device by name
-	class PfRingDeviceList
+	class PfRingDeviceList : public internal::DeviceListBase<PfRingDevice>
 	{
 	private:
-		std::vector<std::unique_ptr<PfRingDevice>> m_PfRingDeviceList;
+		using Base = internal::DeviceListBase<PfRingDevice>;
+
 		std::vector<PfRingDevice*> m_PfRingDeviceListView;
 		std::string m_PfRingVersion;
 
@@ -27,6 +30,7 @@ namespace pcpp
 		PfRingDeviceList(PfRingDeviceList&&) noexcept = delete;
 		PfRingDeviceList& operator=(const PfRingDeviceList&) = delete;
 		PfRingDeviceList& operator=(PfRingDeviceList&&) noexcept = delete;
+		~PfRingDeviceList() = default;
 
 		/// A static method that returns the singleton object for PfRingDeviceList
 		/// @return PfRingDeviceList singleton
@@ -38,6 +42,8 @@ namespace pcpp
 
 		/// Return a list of all available PF_RING devices
 		/// @return a list of all available PF_RING devices
+		/// @deprecated This method has been deprecated in favor of direct accessor API.
+		PCPP_DEPRECATED("Deprecated in favor of direct accessor API")
 		const std::vector<PfRingDevice*>& getPfRingDevicesList() const
 		{
 			return m_PfRingDeviceListView;
@@ -46,7 +52,17 @@ namespace pcpp
 		/// Get a PF_RING device by name. The name is the Linux interface name which appears in ifconfig
 		/// (e.g eth0, eth1, etc.)
 		/// @return A pointer to the PF_RING device
-		PfRingDevice* getPfRingDeviceByName(const std::string& devName) const;
+		PfRingDevice* getDeviceByName(const std::string& devName) const;
+
+		/// Get a PF_RING device by name. The name is the Linux interface name which appears in ifconfig
+		/// (e.g eth0, eth1, etc.)
+		/// @return A pointer to the PF_RING device
+		/// @deprecated This method has been deprecated in favor of getDeviceByName(...).
+		PCPP_DEPRECATED("Please use getDeviceByName(...) instead.")
+		PfRingDevice* getPfRingDeviceByName(const std::string& devName) const
+		{
+			return getDeviceByName(devName);
+		}
 
 		/// Get installed PF_RING version
 		/// @return A string representing PF_RING version
diff --git a/Pcap++/src/DpdkDeviceList.cpp b/Pcap++/src/DpdkDeviceList.cpp
index 933173470..1b8ff9815 100644
--- a/Pcap++/src/DpdkDeviceList.cpp
+++ b/Pcap++/src/DpdkDeviceList.cpp
@@ -34,6 +34,7 @@
 #include <rte_mbuf.h>
 #include <rte_version.h>
 
+#include <memory>
 #include <sstream>
 #include <iomanip>
 #include <string>
@@ -61,16 +62,6 @@ namespace pcpp
 		m_IsInitialized = false;
 	}
 
-	DpdkDeviceList::~DpdkDeviceList()
-	{
-		for (auto dev : m_DpdkDeviceList)
-		{
-			delete dev;
-		}
-
-		m_DpdkDeviceList.clear();
-	}
-
 	bool DpdkDeviceList::initDpdk(CoreMask coreMask, uint32_t mBufPoolSizePerDevice, uint16_t mBufDataSize,
 	                              uint8_t masterCore, uint32_t initDpdkArgc, char** initDpdkArgv,
 	                              const std::string& appName, bool verifyHugePagesAndDriver)
@@ -194,13 +185,17 @@ namespace pcpp
 		// Initialize a DpdkDevice per port
 		for (int i = 0; i < numOfPorts; i++)
 		{
-			DpdkDevice* newDevice = new DpdkDevice(i, mBufPoolSizePerDevice, mBufDataSize);
+			auto newDevice = std::unique_ptr<DpdkDevice>(new DpdkDevice(i, mBufPoolSizePerDevice, mBufDataSize));
 			PCPP_LOG_DEBUG("DpdkDevice #" << i << ": Name='" << newDevice->getDeviceName() << "', PCI-slot='"
 			                              << newDevice->getPciAddress() << "', PMD='" << newDevice->getPMDName()
 			                              << "', MAC Addr='" << newDevice->getMacAddress() << "'");
-			m_DpdkDeviceList.push_back(newDevice);
+			m_DeviceList.pushBack(std::move(newDevice));
 		}
 
+		// Full update of all elements of the view vector to synchronize them with the main vector.
+		m_DpdkDeviceListView.resize(m_DeviceList.size());
+		std::copy(m_DeviceList.begin(), m_DeviceList.end(), m_DpdkDeviceListView.begin());
+
 		m_IsInitialized = true;
 		return true;
 	}
@@ -213,12 +208,13 @@ namespace pcpp
 			return nullptr;
 		}
 
-		if ((uint32_t)portId >= m_DpdkDeviceList.size())
+		if (static_cast<std::size_t>(portId) >= m_DeviceList.size())
 		{
 			return nullptr;
 		}
 
-		return m_DpdkDeviceList.at(portId);
+		// Hack because the device list returns a pointer to const, when the device list is const qualified.
+		return const_cast<DpdkDevice*>(m_DeviceList.at(portId));
 	}
 
 	DpdkDevice* DpdkDeviceList::getDeviceByPciAddress(const std::string& pciAddr) const
@@ -229,10 +225,10 @@ namespace pcpp
 			return nullptr;
 		}
 
-		auto devIter = std::find_if(m_DpdkDeviceList.begin(), m_DpdkDeviceList.end(),
+		auto devIter = std::find_if(m_DeviceList.begin(), m_DeviceList.end(),
 		                            [&pciAddr](const DpdkDevice* dev) { return dev->getPciAddress() == pciAddr; });
 
-		if (devIter == m_DpdkDeviceList.end())
+		if (devIter == m_DeviceList.end())
 		{
 			PCPP_LOG_DEBUG("Found no DPDK devices with PCI address '" << pciAddr << "'");
 			return nullptr;
diff --git a/Pcap++/src/KniDeviceList.cpp b/Pcap++/src/KniDeviceList.cpp
index 1b639c14f..d153e6bc1 100644
--- a/Pcap++/src/KniDeviceList.cpp
+++ b/Pcap++/src/KniDeviceList.cpp
@@ -37,9 +37,8 @@ namespace pcpp
 		return true;
 	}
 
-	KniDeviceList::KniDeviceList() : m_Devices(), m_Initialized(true), m_KniUniqueId(0)
+	KniDeviceList::KniDeviceList() : m_Initialized(true), m_KniUniqueId(0)
 	{
-		m_Devices.reserve(MAX_KNI_DEVICES);
 		if (!checkKniDriver())
 		{
 			m_Initialized = false;
@@ -63,8 +62,7 @@ namespace pcpp
 
 	KniDeviceList::~KniDeviceList()
 	{
-		for (size_t i = 0; i < m_Devices.size(); ++i)
-			delete m_Devices[i];
+		m_DeviceList.clear();
 		rte_kni_close();
 	}
 
@@ -77,33 +75,34 @@ namespace pcpp
 	KniDevice* KniDeviceList::createDevice(const KniDevice::KniDeviceConfiguration& config, const size_t mempoolSize)
 	{
 		if (!isInitialized())
+		{
 			return nullptr;
-		KniDevice* kniDevice = getDeviceByName(std::string(config.name));
-		if (kniDevice != nullptr)
+		}
+
+		if (getDeviceByName(std::string(config.name)) != nullptr)
 		{
 			PCPP_LOG_ERROR("Attempt to create DPDK KNI device with same name: '" << config.name << "'");
 			PCPP_LOG_DEBUG("Use KniDeviceList::getDeviceByName or KniDeviceList::getDeviceByPort.");
 			return nullptr;
 		}
-		if (config.portId != UINT16_MAX)
+		if (config.portId != UINT16_MAX && getDeviceByPort(config.portId) != nullptr)
 		{
-			kniDevice = getDeviceByPort(config.portId);
-			if (kniDevice != nullptr)
-			{
-				PCPP_LOG_ERROR("Attempt to create DPDK KNI device with same port ID: " << config.portId);
-				PCPP_LOG_DEBUG("Use KniDeviceList::getDeviceByName or KniDeviceList::getDeviceByPort.");
-				return nullptr;
-			}
+			PCPP_LOG_ERROR("Attempt to create DPDK KNI device with same port ID: " << config.portId);
+			PCPP_LOG_DEBUG("Use KniDeviceList::getDeviceByName or KniDeviceList::getDeviceByPort.");
+			return nullptr;
 		}
-		kniDevice = new KniDevice(config, mempoolSize, m_KniUniqueId++);
-		m_Devices.push_back(kniDevice);
+		auto kniDevice = new KniDevice(config, mempoolSize, m_KniUniqueId++);
+		m_DeviceList.pushBack(kniDevice);
 		return kniDevice;
 	}
 
 	void KniDeviceList::destroyDevice(KniDevice* kniDevice)
 	{
-		m_Devices.erase(std::remove(m_Devices.begin(), m_Devices.end(), kniDevice), m_Devices.end());
-		delete kniDevice;
+		auto it = std::find(m_DeviceList.begin(), m_DeviceList.end(), kniDevice);
+		if (it != m_DeviceList.end())
+		{
+			m_DeviceList.erase(it);
+		}
 	}
 
 	KniDevice* KniDeviceList::getDeviceByPort(const uint16_t portId)
@@ -111,30 +110,23 @@ namespace pcpp
 		//? Linear search here is optimal for low count of devices.
 		//? We assume that no one will create large count of devices or will rapidly search them.
 		//? Same for <getDeviceByName> function
-		KniDevice* kniDevice = nullptr;
 		if (!isInitialized())
-			return kniDevice;
-		for (size_t i = 0; i < m_Devices.size(); ++i)
-		{
-			kniDevice = m_Devices[i];
-			if (kniDevice && kniDevice->m_DeviceInfo.portId == portId)
-				return kniDevice;
-		}
-		return kniDevice = nullptr;
+			return nullptr;
+
+		auto const foundIt = std::find_if(m_DeviceList.begin(), m_DeviceList.end(), [&portId](KniDevice* kniDevice) {
+			return kniDevice && kniDevice->m_DeviceInfo.portId == portId;
+		});
+		return foundIt != m_DeviceList.end() ? *foundIt : nullptr;
 	}
 
 	KniDevice* KniDeviceList::getDeviceByName(const std::string& name)
 	{
-		KniDevice* kniDevice = nullptr;
 		if (!isInitialized())
-			return kniDevice;
-		for (size_t i = 0; i < m_Devices.size(); ++i)
-		{
-			kniDevice = m_Devices[i];
-			if (kniDevice && kniDevice->m_DeviceInfo.name == name)
-				return kniDevice;
-		}
-		return kniDevice = nullptr;
+			return nullptr;
+		auto const foundIt = std::find_if(m_DeviceList.begin(), m_DeviceList.end(), [&name](KniDevice* kniDevice) {
+			return kniDevice && kniDevice->m_DeviceInfo.name == name;
+		});
+		return foundIt != m_DeviceList.end() ? *foundIt : nullptr;
 	}
 
 	KniDeviceList::KniCallbackVersion KniDeviceList::callbackVersion()
diff --git a/Pcap++/src/PcapLiveDeviceList.cpp b/Pcap++/src/PcapLiveDeviceList.cpp
index 9fb46b4ce..5d3747b2d 100644
--- a/Pcap++/src/PcapLiveDeviceList.cpp
+++ b/Pcap++/src/PcapLiveDeviceList.cpp
@@ -26,24 +26,23 @@ namespace pcpp
 {
 	namespace
 	{
-		void syncPointerVectors(std::vector<std::unique_ptr<PcapLiveDevice>> const& mainVector,
+		void syncPointerVectors(PointerVector<PcapLiveDevice> const& mainVector,
 		                        std::vector<PcapLiveDevice*>& viewVector)
 		{
 			viewVector.resize(mainVector.size());
 			// Full update of all elements of the view vector to synchronize them with the main vector.
-			std::transform(mainVector.begin(), mainVector.end(), viewVector.begin(),
-			               [](const std::unique_ptr<PcapLiveDevice>& ptr) { return ptr.get(); });
+			std::copy(mainVector.begin(), mainVector.end(), viewVector.begin());
 		}
 	}  // namespace
 
-	PcapLiveDeviceList::PcapLiveDeviceList() : m_LiveDeviceList(fetchAllLocalDevices()), m_DnsServers(fetchDnsServers())
+	PcapLiveDeviceList::PcapLiveDeviceList() : Base(fetchAllLocalDevices()), m_DnsServers(fetchDnsServers())
 	{
-		syncPointerVectors(m_LiveDeviceList, m_LiveDeviceListView);
+		syncPointerVectors(m_DeviceList, m_LiveDeviceListView);
 	}
 
-	std::vector<std::unique_ptr<PcapLiveDevice>> PcapLiveDeviceList::fetchAllLocalDevices()
+	PointerVector<PcapLiveDevice> PcapLiveDeviceList::fetchAllLocalDevices()
 	{
-		std::vector<std::unique_ptr<PcapLiveDevice>> deviceList;
+		PointerVector<PcapLiveDevice> deviceList;
 		std::unique_ptr<pcap_if_t, internal::PcapFreeAllDevsDeleter> interfaceList;
 		try
 		{
@@ -64,7 +63,7 @@ namespace pcpp
 #else  //__linux__, __APPLE__, __FreeBSD__
 			auto dev = std::unique_ptr<PcapLiveDevice>(new PcapLiveDevice(currInterface, true, true, true));
 #endif
-			deviceList.push_back(std::move(dev));
+			deviceList.pushBack(std::move(dev));
 		}
 		return deviceList;
 	}
@@ -264,39 +263,39 @@ namespace pcpp
 		return dnsServers;
 	}
 
-	PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(const IPAddress& ipAddr) const
+	PcapLiveDevice* PcapLiveDeviceList::getDeviceByIp(const IPAddress& ipAddr) const
 	{
-		if (ipAddr.getType() == IPAddress::IPv4AddressType)
+		switch (ipAddr.getType())
 		{
-			return getPcapLiveDeviceByIp(ipAddr.getIPv4());
-		}
-		else  // IPAddress::IPv6AddressType
-		{
-			return getPcapLiveDeviceByIp(ipAddr.getIPv6());
+		case IPAddress::IPv4AddressType:
+			return getDeviceByIp(ipAddr.getIPv4());
+		case IPAddress::IPv6AddressType:
+			return getDeviceByIp(ipAddr.getIPv6());
+		default:
+			PCPP_LOG_ERROR("Unknown IP address type: " << ipAddr.getType());
+			return nullptr;
 		}
 	}
 
-	PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(const IPv4Address& ipAddr) const
+	PcapLiveDevice* PcapLiveDeviceList::getDeviceByIp(const IPv4Address& ipAddr) const
 	{
-		auto it = std::find_if(m_LiveDeviceList.begin(), m_LiveDeviceList.end(),
-		                       [&ipAddr](std::unique_ptr<PcapLiveDevice> const& devPtr) {
-			                       auto devIP = devPtr->getIPv4Address();
-			                       return devIP == ipAddr;
-		                       });
-		return it != m_LiveDeviceList.end() ? it->get() : nullptr;
+		auto it = std::find_if(m_DeviceList.begin(), m_DeviceList.end(), [&ipAddr](PcapLiveDevice const* devPtr) {
+			auto devIP = devPtr->getIPv4Address();
+			return devIP == ipAddr;
+		});
+		return it != m_DeviceList.end() ? *it : nullptr;
 	}
 
-	PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(const IPv6Address& ip6Addr) const
+	PcapLiveDevice* PcapLiveDeviceList::getDeviceByIp(const IPv6Address& ip6Addr) const
 	{
-		auto it = std::find_if(m_LiveDeviceList.begin(), m_LiveDeviceList.end(),
-		                       [&ip6Addr](std::unique_ptr<PcapLiveDevice> const& devPtr) {
-			                       auto devIP = devPtr->getIPv6Address();
-			                       return devIP == ip6Addr;
-		                       });
-		return it != m_LiveDeviceList.end() ? it->get() : nullptr;
+		auto it = std::find_if(m_DeviceList.begin(), m_DeviceList.end(), [&ip6Addr](PcapLiveDevice const* devPtr) {
+			auto devIP = devPtr->getIPv6Address();
+			return devIP == ip6Addr;
+		});
+		return it != m_DeviceList.end() ? *it : nullptr;
 	}
 
-	PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(const std::string& ipAddrAsString) const
+	PcapLiveDevice* PcapLiveDeviceList::getDeviceByIp(const std::string& ipAddrAsString) const
 	{
 		IPAddress ipAddr;
 		try
@@ -309,36 +308,35 @@ namespace pcpp
 			return nullptr;
 		}
 
-		PcapLiveDevice* result = PcapLiveDeviceList::getPcapLiveDeviceByIp(ipAddr);
+		PcapLiveDevice* result = PcapLiveDeviceList::getDeviceByIp(ipAddr);
 		return result;
 	}
 
-	PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByName(const std::string& name) const
+	PcapLiveDevice* PcapLiveDeviceList::getDeviceByName(const std::string& name) const
 	{
 		PCPP_LOG_DEBUG("Searching all live devices...");
-		auto devIter =
-		    std::find_if(m_LiveDeviceList.begin(), m_LiveDeviceList.end(),
-		                 [&name](const std::unique_ptr<PcapLiveDevice>& dev) { return dev->getName() == name; });
+		auto devIter = std::find_if(m_DeviceList.begin(), m_DeviceList.end(),
+		                            [&name](PcapLiveDevice const* dev) { return dev->getName() == name; });
 
-		if (devIter == m_LiveDeviceList.end())
+		if (devIter == m_DeviceList.end())
 		{
 			PCPP_LOG_DEBUG("Found no live device with name '" << name << "'");
 			return nullptr;
 		}
 
-		return devIter->get();
+		return *devIter;
 	}
 
-	PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIpOrName(const std::string& ipOrName) const
+	PcapLiveDevice* PcapLiveDeviceList::getDeviceByIpOrName(const std::string& ipOrName) const
 	{
 		try
 		{
 			IPAddress interfaceIP = IPAddress(ipOrName);
-			return PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(interfaceIP);
+			return PcapLiveDeviceList::getInstance().getDeviceByIp(interfaceIP);
 		}
 		catch (std::exception&)
 		{
-			return PcapLiveDeviceList::getInstance().getPcapLiveDeviceByName(ipOrName);
+			return PcapLiveDeviceList::getInstance().getDeviceByName(ipOrName);
 		}
 	}
 
@@ -351,10 +349,10 @@ namespace pcpp
 	{
 		m_LiveDeviceListView.clear();
 
-		m_LiveDeviceList = fetchAllLocalDevices();
+		m_DeviceList = fetchAllLocalDevices();
 		m_DnsServers = fetchDnsServers();
 
-		syncPointerVectors(m_LiveDeviceList, m_LiveDeviceListView);
+		syncPointerVectors(m_DeviceList, m_LiveDeviceListView);
 	}
 
 }  // namespace pcpp
diff --git a/Pcap++/src/PcapRemoteDeviceList.cpp b/Pcap++/src/PcapRemoteDeviceList.cpp
index 01791d6dd..e759b5f6f 100644
--- a/Pcap++/src/PcapRemoteDeviceList.cpp
+++ b/Pcap++/src/PcapRemoteDeviceList.cpp
@@ -7,6 +7,7 @@
 #include "IpAddressUtils.h"
 #include "pcap.h"
 #include <array>
+#include <memory>
 #include <ws2tcpip.h>
 
 namespace pcpp
@@ -48,8 +49,8 @@ namespace pcpp
 
 	PcapRemoteDeviceList::PcapRemoteDeviceList(const IPAddress& ipAddress, uint16_t port,
 	                                           std::shared_ptr<PcapRemoteAuthentication> remoteAuth,
-	                                           std::vector<PcapRemoteDevice*> deviceList)
-	    : m_RemoteDeviceList(std::move(deviceList)), m_RemoteMachineIpAddress(ipAddress), m_RemoteMachinePort(port),
+	                                           PointerVector<PcapRemoteDevice> deviceList)
+	    : Base(std::move(deviceList)), m_RemoteMachineIpAddress(ipAddress), m_RemoteMachinePort(port),
 	      m_RemoteAuthentication(std::move(remoteAuth))
 	{}
 
@@ -98,7 +99,7 @@ namespace pcpp
 			return nullptr;
 		}
 
-		std::vector<PcapRemoteDevice*> devices;
+		PointerVector<PcapRemoteDevice> devices;
 		try
 		{
 			for (pcap_if_t* currInterface = interfaceList.get(); currInterface != nullptr;
@@ -106,27 +107,20 @@ namespace pcpp
 			{
 				auto pNewRemoteDevice = std::unique_ptr<PcapRemoteDevice>(
 				    new PcapRemoteDevice(currInterface, pRemoteAuthCopy, ipAddress, port));
-				// Release is called after pushback to prevent memory leaks if vector reallocation fails.
-				// cppcheck-suppress danglingLifetime
-				devices.push_back(pNewRemoteDevice.get());
-				pNewRemoteDevice.release();
+				devices.pushBack(std::move(pNewRemoteDevice));
 			}
 		}
 		catch (const std::exception& e)
 		{
-			for (auto device : devices)
-			{
-				delete device;
-			}
 			PCPP_LOG_ERROR("Error creating remote devices: " << e.what());
 			return nullptr;
 		}
 
 		return std::unique_ptr<PcapRemoteDeviceList>(
-		    new PcapRemoteDeviceList(ipAddress, port, pRemoteAuthCopy, devices));
+		    new PcapRemoteDeviceList(ipAddress, port, pRemoteAuthCopy, std::move(devices)));
 	}
 
-	PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(const std::string& ipAddrAsString) const
+	PcapRemoteDevice* PcapRemoteDeviceList::getDeviceByIp(const std::string& ipAddrAsString) const
 	{
 		IPAddress ipAddr;
 
@@ -140,50 +134,40 @@ namespace pcpp
 			return nullptr;
 		}
 
-		PcapRemoteDevice* result = getRemoteDeviceByIP(ipAddr);
+		PcapRemoteDevice* result = getDeviceByIp(ipAddr);
 		return result;
 	}
 
-	PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(const IPAddress& ipAddr) const
+	PcapRemoteDevice* PcapRemoteDeviceList::getDeviceByIp(const IPAddress& ipAddr) const
 	{
-		if (ipAddr.getType() == IPAddress::IPv4AddressType)
+		switch (ipAddr.getType())
 		{
-			return getRemoteDeviceByIP(ipAddr.getIPv4());
-		}
-		else  // IPAddress::IPv6AddressType
-		{
-			return getRemoteDeviceByIP(ipAddr.getIPv6());
+		case IPAddress::IPv4AddressType:
+			return getDeviceByIp(ipAddr.getIPv4());
+		case IPAddress::IPv6AddressType:
+			return getDeviceByIp(ipAddr.getIPv6());
+		default:
+			PCPP_LOG_ERROR("Unknown IP address type: " << ipAddr.getType());
+			return nullptr;
 		}
 	}
 
-	PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(const IPv4Address& ip4Addr) const
+	PcapRemoteDevice* PcapRemoteDeviceList::getDeviceByIp(const IPv4Address& ip4Addr) const
 	{
-		auto it = std::find_if(m_RemoteDeviceList.begin(), m_RemoteDeviceList.end(),
-		                       [&ip4Addr](PcapRemoteDevice const* devPtr) {
-			                       auto devIP = devPtr->getIPv4Address();
-			                       return devIP == ip4Addr;
-		                       });
-		return it != m_RemoteDeviceList.end() ? *it : nullptr;
+		auto it = std::find_if(m_DeviceList.begin(), m_DeviceList.end(), [&ip4Addr](PcapRemoteDevice const* devPtr) {
+			auto devIP = devPtr->getIPv4Address();
+			return devIP == ip4Addr;
+		});
+		return it != m_DeviceList.end() ? *it : nullptr;
 	}
 
-	PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(const IPv6Address& ip6Addr) const
+	PcapRemoteDevice* PcapRemoteDeviceList::getDeviceByIp(const IPv6Address& ip6Addr) const
 	{
-		auto it = std::find_if(m_RemoteDeviceList.begin(), m_RemoteDeviceList.end(),
-		                       [&ip6Addr](PcapRemoteDevice const* devPtr) {
-			                       auto devIP = devPtr->getIPv6Address();
-			                       return devIP == ip6Addr;
-		                       });
-		return it != m_RemoteDeviceList.end() ? *it : nullptr;
-	}
-
-	PcapRemoteDeviceList::~PcapRemoteDeviceList()
-	{
-		while (m_RemoteDeviceList.size() > 0)
-		{
-			RemoteDeviceListIterator devIter = m_RemoteDeviceList.begin();
-			delete (*devIter);
-			m_RemoteDeviceList.erase(devIter);
-		}
+		auto it = std::find_if(m_DeviceList.begin(), m_DeviceList.end(), [&ip6Addr](PcapRemoteDevice const* devPtr) {
+			auto devIP = devPtr->getIPv6Address();
+			return devIP == ip6Addr;
+		});
+		return it != m_DeviceList.end() ? *it : nullptr;
 	}
 
 }  // namespace pcpp
diff --git a/Pcap++/src/PfRingDeviceList.cpp b/Pcap++/src/PfRingDeviceList.cpp
index bd1be57d7..66eb7cba0 100644
--- a/Pcap++/src/PfRingDeviceList.cpp
+++ b/Pcap++/src/PfRingDeviceList.cpp
@@ -4,6 +4,7 @@
 
 #include <cstdio>
 #include <array>
+#include <memory>
 #include "PfRingDeviceList.h"
 #include "SystemUtils.h"
 #include "DeviceUtils.h"
@@ -93,7 +94,7 @@ namespace pcpp
 					}
 					std::unique_ptr<PfRingDevice> newDev =
 					    std::unique_ptr<PfRingDevice>(new PfRingDevice(currInterface->name));
-					m_PfRingDeviceList.push_back(std::move(newDev));
+					m_DeviceList.pushBack(std::move(newDev));
 					PCPP_LOG_DEBUG("Found interface: " << currInterface->name);
 				}
 			}
@@ -106,25 +107,23 @@ namespace pcpp
 		PCPP_LOG_DEBUG("PfRingDeviceList init end");
 
 		// Full update of all elements of the view vector to synchronize them with the main vector.
-		m_PfRingDeviceListView.resize(m_PfRingDeviceList.size());
-		std::transform(m_PfRingDeviceList.begin(), m_PfRingDeviceList.end(), m_PfRingDeviceListView.begin(),
-		               [](const std::unique_ptr<PfRingDevice>& ptr) { return ptr.get(); });
+		m_PfRingDeviceListView.resize(m_DeviceList.size());
+		std::copy(m_DeviceList.begin(), m_DeviceList.end(), m_PfRingDeviceListView.begin());
 	}
 
-	PfRingDevice* PfRingDeviceList::getPfRingDeviceByName(const std::string& devName) const
+	PfRingDevice* PfRingDeviceList::getDeviceByName(const std::string& devName) const
 	{
 		PCPP_LOG_DEBUG("Searching all live devices...");
-		auto devIter = std::find_if(
-		    m_PfRingDeviceList.begin(), m_PfRingDeviceList.end(),
-		    [&devName](const std::unique_ptr<PfRingDevice>& dev) { return dev->getDeviceName() == devName; });
+		auto devIter = std::find_if(m_DeviceList.begin(), m_DeviceList.end(),
+		                            [&devName](PfRingDevice const* dev) { return dev->getDeviceName() == devName; });
 
-		if (devIter == m_PfRingDeviceList.end())
+		if (devIter == m_DeviceList.end())
 		{
 			PCPP_LOG_DEBUG("Found no PF_RING devices with name '" << devName << "'");
 			return nullptr;
 		}
 
-		return devIter->get();
+		return *devIter;
 	}
 }  // namespace pcpp
 
diff --git a/Tests/Pcap++Test/CMakeLists.txt b/Tests/Pcap++Test/CMakeLists.txt
index 07262ffb8..36a98e6dd 100644
--- a/Tests/Pcap++Test/CMakeLists.txt
+++ b/Tests/Pcap++Test/CMakeLists.txt
@@ -2,6 +2,7 @@ add_executable(
   Pcap++Test
   Common/TestUtils.cpp
   main.cpp
+  Tests/DeviceListBaseTests.cpp
   Tests/DpdkTests.cpp
   Tests/FileTests.cpp
   Tests/FilterTests.cpp
diff --git a/Tests/Pcap++Test/TestDefinition.h b/Tests/Pcap++Test/TestDefinition.h
index ccaaec475..469e280bc 100644
--- a/Tests/Pcap++Test/TestDefinition.h
+++ b/Tests/Pcap++Test/TestDefinition.h
@@ -32,6 +32,9 @@ PTF_TEST_CASE(TestSolarisSnoopFileRead);
 PTF_TEST_CASE(TestPcapNgFilePrecision);
 PTF_TEST_CASE(TestPcapFileWriterDeviceDestructor);
 
+// Implemented in DeviceListBaseTests.cpp
+PTF_TEST_CASE(TestDeviceListBase);
+
 // Implemented in LiveDeviceTests.cpp
 PTF_TEST_CASE(TestPcapLiveDeviceList);
 PTF_TEST_CASE(TestPcapLiveDeviceListSearch);
diff --git a/Tests/Pcap++Test/Tests/DeviceListBaseTests.cpp b/Tests/Pcap++Test/Tests/DeviceListBaseTests.cpp
new file mode 100644
index 000000000..0a40115d3
--- /dev/null
+++ b/Tests/Pcap++Test/Tests/DeviceListBaseTests.cpp
@@ -0,0 +1,69 @@
+#include "../TestDefinition.h"
+
+#include "DeviceListBase.h"
+
+namespace
+{
+	/// @brief A derived class of DeviceListBase used for testing purposes.
+	template <class T> struct DerivedDeviceList : public pcpp::internal::DeviceListBase<T>
+	{
+		DerivedDeviceList() = default;
+		explicit DerivedDeviceList(pcpp::PointerVector<T> devices)
+		    : pcpp::internal::DeviceListBase<T>(std::move(devices))
+		{}
+	};
+
+}  // namespace
+
+PTF_TEST_CASE(TestDeviceListBase)
+{
+	using pcpp::internal::DeviceListBase;
+
+	// Test the default constructor.
+	DerivedDeviceList<int> deviceList;
+	PTF_ASSERT_EQUAL(deviceList.size(), 0);
+	PTF_ASSERT_TRUE(deviceList.begin() == deviceList.end());
+	PTF_ASSERT_TRUE(deviceList.empty());
+
+	// Test the constructor with a list of devices.
+	pcpp::PointerVector<int> devices;
+	int* dev0 = new int(0);
+	int* dev1 = new int(1);
+	int* dev2 = new int(2);
+	devices.pushBack(dev0);
+	devices.pushBack(dev1);
+	devices.pushBack(dev2);
+	DerivedDeviceList<int> deviceList2(std::move(devices));
+
+	PTF_ASSERT_EQUAL(deviceList2.size(), 3);
+	PTF_ASSERT_FALSE(deviceList2.empty());
+	PTF_ASSERT_EQUAL(deviceList2.at(0), dev0);
+	PTF_ASSERT_EQUAL(deviceList2.at(1), dev1);
+	PTF_ASSERT_EQUAL(deviceList2.at(2), dev2);
+	PTF_ASSERT_EQUAL(deviceList2.front(), dev0);
+	PTF_ASSERT_EQUAL(deviceList2.back(), dev2);
+
+	// Test iterators.
+	{
+		auto it = deviceList2.begin();
+		PTF_ASSERT_EQUAL(*it, dev0);
+		++it;
+		PTF_ASSERT_EQUAL(*it, dev1);
+		++it;
+		PTF_ASSERT_EQUAL(*it, dev2);
+		++it;
+		PTF_ASSERT_TRUE(it == deviceList2.end());
+	}
+
+	// Test const iterators.
+	{
+		auto it = deviceList2.cbegin();
+		PTF_ASSERT_EQUAL(*it, dev0);
+		++it;
+		PTF_ASSERT_EQUAL(*it, dev1);
+		++it;
+		PTF_ASSERT_EQUAL(*it, dev2);
+		++it;
+		PTF_ASSERT_TRUE(it == deviceList2.cend());
+	}
+}
diff --git a/Tests/Pcap++Test/Tests/FilterTests.cpp b/Tests/Pcap++Test/Tests/FilterTests.cpp
index bb2305937..579e8cbb4 100644
--- a/Tests/Pcap++Test/Tests/FilterTests.cpp
+++ b/Tests/Pcap++Test/Tests/FilterTests.cpp
@@ -36,7 +36,7 @@ PTF_TEST_CASE(TestPcapFiltersLive)
 {
 	pcpp::PcapLiveDevice* liveDev = nullptr;
 	pcpp::IPv4Address ipToSearch(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ipToSearch);
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(ipToSearch);
 	PTF_ASSERT_NOT_NULL(liveDev);
 
 	std::string filterAsString;
diff --git a/Tests/Pcap++Test/Tests/IpMacTests.cpp b/Tests/Pcap++Test/Tests/IpMacTests.cpp
index 84a8c1475..1a93822ce 100644
--- a/Tests/Pcap++Test/Tests/IpMacTests.cpp
+++ b/Tests/Pcap++Test/Tests/IpMacTests.cpp
@@ -355,7 +355,7 @@ PTF_TEST_CASE(TestGetMacAddress)
 {
 	pcpp::PcapLiveDevice* liveDev = nullptr;
 	pcpp::IPv4Address ipToSearch(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ipToSearch);
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(ipToSearch);
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_TRUE(liveDev->open());
 	DeviceTeardown devTeardown(liveDev);
diff --git a/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp b/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp
index 19d4954a0..90757b6d2 100644
--- a/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp
+++ b/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp
@@ -11,6 +11,8 @@
 #include "../Common/TestUtils.h"
 #include "../Common/PcapFileNamesDef.h"
 #include <array>
+#include <memory>
+#include <utility>
 #include <vector>
 #include <iterator>
 #include <algorithm>
@@ -225,7 +227,7 @@ class RpcapdServerInitializer
 
 PTF_TEST_CASE(TestPcapLiveDeviceList)
 {
-	std::vector<pcpp::PcapLiveDevice*> devList = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
+	auto& devList = pcpp::PcapLiveDeviceList::getInstance();
 	PTF_ASSERT_FALSE(devList.empty());
 
 	pcpp::IPv4Address defaultGateway = pcpp::IPv4Address::Zero;
@@ -244,7 +246,6 @@ PTF_TEST_CASE(TestPcapLiveDeviceList)
 	// reset the device list and make sure devices are back and there is no memory leak
 	pcpp::PcapLiveDeviceList::getInstance().reset();
 
-	devList = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
 	PTF_ASSERT_FALSE(devList.empty());
 
 	for (const auto& iter : devList)
@@ -252,18 +253,18 @@ PTF_TEST_CASE(TestPcapLiveDeviceList)
 		PTF_ASSERT_FALSE(iter->getName().empty());
 	}
 
-	pcpp::PcapLiveDeviceList* clonedDevList = pcpp::PcapLiveDeviceList::getInstance().clone();
-	PTF_ASSERT_NOT_NULL(clonedDevList);
+	{
+		auto clonedDevList = std::unique_ptr<pcpp::PcapLiveDeviceList>(devList.clone());
+		PTF_ASSERT_NOT_NULL(clonedDevList);
 
-	std::vector<pcpp::PcapLiveDevice*> clonedDevListVector = clonedDevList->getPcapLiveDevicesList();
-	PTF_ASSERT_EQUAL(clonedDevListVector.size(), devList.size());
+		PTF_ASSERT_EQUAL(clonedDevList->size(), devList.size());
 
-	auto iterCloned = clonedDevListVector.begin();
-	for (auto iter = devList.begin(); iter != devList.end(); ++iter, ++iterCloned)
-	{
-		PTF_ASSERT_EQUAL((*iter)->getName(), (*iterCloned)->getName());
+		for (auto itPair = std::make_pair(devList.begin(), clonedDevList->begin()); itPair.first != devList.end();
+		     ++itPair.first, ++itPair.second)
+		{
+			PTF_ASSERT_EQUAL((*itPair.first)->getName(), (*itPair.second)->getName());
+		}
 	}
-	delete clonedDevList;
 
 	PTF_ASSERT_EQUAL(pcpp::PcapLiveDeviceList::getInstance().getDnsServers().size(), dnsServerCount);
 }  // TestPcapLiveDeviceList
@@ -271,23 +272,21 @@ PTF_TEST_CASE(TestPcapLiveDeviceList)
 PTF_TEST_CASE(TestPcapLiveDeviceListSearch)
 {
 	pcpp::PcapLiveDevice* liveDev = nullptr;
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(liveDev);
 
 	std::string devName(liveDev->getName());
 	pcpp::PcapLiveDevice* liveDev2 = nullptr;
-	liveDev2 = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByName(devName);
+	liveDev2 = pcpp::PcapLiveDeviceList::getInstance().getDeviceByName(devName);
 	PTF_ASSERT_NOT_NULL(liveDev2);
 	PTF_ASSERT_EQUAL(liveDev->getName(), liveDev2->getName());
 
-	pcpp::PcapLiveDevice* liveDev3 = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(devName);
+	pcpp::PcapLiveDevice* liveDev3 = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIpOrName(devName);
 	PTF_ASSERT_EQUAL(liveDev3, liveDev2, ptr);
-	liveDev3 =
-	    pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(PcapTestGlobalArgs.ipToSendReceivePackets);
+	liveDev3 = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIpOrName(PcapTestGlobalArgs.ipToSendReceivePackets);
 	PTF_ASSERT_EQUAL(liveDev3, liveDev, ptr);
 
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp("255.255.255.250");
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp("255.255.255.250");
 	PTF_ASSERT_NULL(liveDev);
 }  // TestPcapLiveDeviceListSearch
 
@@ -295,7 +294,7 @@ PTF_TEST_CASE(TestPcapLiveDevice)
 {
 	pcpp::PcapLiveDevice* liveDev = nullptr;
 	pcpp::IPv4Address ipToSearch(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ipToSearch);
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(ipToSearch);
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_GREATER_THAN(liveDev->getMtu(), 0);
 	PTF_ASSERT_TRUE(liveDev->open());
@@ -349,7 +348,7 @@ PTF_TEST_CASE(TestPcapLiveDeviceClone)
 	pcpp::IPv4Address ipToSearch(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 
 	{
-		pcpp::PcapLiveDevice* originalDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ipToSearch);
+		pcpp::PcapLiveDevice* originalDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(ipToSearch);
 		PTF_ASSERT_NOT_NULL(originalDev);
 
 #ifdef _WIN32
@@ -409,7 +408,7 @@ PTF_TEST_CASE(TestPcapLiveDeviceNoNetworking)
 
 	pcpp::PcapLiveDevice* liveDev = nullptr;
 
-	std::vector<pcpp::PcapLiveDevice*> devList = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList();
+	auto& devList = pcpp::PcapLiveDeviceList::getInstance();
 	PTF_ASSERT_FALSE(devList.empty());
 
 	auto iter = std::find_if(devList.begin(), devList.end(), [](const pcpp::PcapLiveDevice* dev) {
@@ -428,7 +427,7 @@ PTF_TEST_CASE(TestPcapLiveDeviceNoNetworking)
 	// a negative test - check invalid IP address
 	liveDev = nullptr;
 	pcpp::Logger::getInstance().suppressLogs();
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp("eth0");
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp("eth0");
 	pcpp::Logger::getInstance().enableLogs();
 	PTF_ASSERT_NULL(liveDev);
 
@@ -436,8 +435,8 @@ PTF_TEST_CASE(TestPcapLiveDeviceNoNetworking)
 
 PTF_TEST_CASE(TestPcapLiveDeviceStatsMode)
 {
-	pcpp::PcapLiveDevice* liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* liveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_TRUE(liveDev->open());
 	DeviceTeardown devTeardown(liveDev);
@@ -487,8 +486,8 @@ PTF_TEST_CASE(TestPcapLiveDeviceBlockingMode)
 	for (const auto& config : configs)
 	{
 		// open device
-		pcpp::PcapLiveDevice* liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-		    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+		pcpp::PcapLiveDevice* liveDev =
+		    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 		PTF_ASSERT_NOT_NULL(liveDev);
 		PTF_ASSERT_TRUE(liveDev->open(config));
 		DeviceTeardown devTeardown(liveDev);
@@ -578,7 +577,7 @@ PTF_TEST_CASE(TestPcapLiveDeviceWithLambda)
 {
 	pcpp::PcapLiveDevice* liveDev = nullptr;
 	pcpp::IPv4Address ipToSearch(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ipToSearch);
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(ipToSearch);
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_GREATER_THAN(liveDev->getMtu(), 0);
 	PTF_ASSERT_TRUE(liveDev->open());
@@ -625,8 +624,8 @@ PTF_TEST_CASE(TestPcapLiveDeviceBlockingModeWithLambda)
 	};
 
 	// open device
-	pcpp::PcapLiveDevice* liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* liveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_TRUE(liveDev->open());
 	DeviceTeardown devTeardown(liveDev);
@@ -645,8 +644,8 @@ PTF_TEST_CASE(TestPcapLiveDeviceBlockingModeWithLambda)
 
 PTF_TEST_CASE(TestPcapLiveDeviceSpecialCfg)
 {
-	pcpp::PcapLiveDevice* liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* liveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(liveDev);
 
 	// open device in default mode
@@ -717,8 +716,8 @@ PTF_TEST_CASE(TestWinPcapLiveDevice)
 {
 #if defined(_WIN32)
 
-	pcpp::PcapLiveDevice* liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* liveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_EQUAL(liveDev->getDeviceType(), pcpp::PcapLiveDevice::WinPcapDevice, enum);
 
@@ -754,8 +753,8 @@ PTF_TEST_CASE(TestWinPcapLiveDevice)
 	pcpp::Logger::getInstance().enableLogs();
 
 #else
-	pcpp::PcapLiveDevice* liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* liveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_EQUAL(liveDev->getDeviceType(), pcpp::PcapLiveDevice::LibPcapDevice, enum);
 #endif
@@ -766,7 +765,7 @@ PTF_TEST_CASE(TestSendPacket)
 {
 	pcpp::PcapLiveDevice* liveDev = nullptr;
 	pcpp::IPv4Address ipToSearch(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ipToSearch);
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(ipToSearch);
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_TRUE(liveDev->open());
 	DeviceTeardown devTeardown(liveDev);
@@ -815,7 +814,7 @@ PTF_TEST_CASE(TestSendPackets)
 {
 	pcpp::PcapLiveDevice* liveDev = nullptr;
 	pcpp::IPv4Address ipToSearch(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ipToSearch);
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(ipToSearch);
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_TRUE(liveDev->open());
 	DeviceTeardown devTeardown(liveDev);
@@ -852,7 +851,7 @@ PTF_TEST_CASE(TestMtuSize)
 {
 	pcpp::PcapLiveDevice* liveDev = nullptr;
 	pcpp::IPv4Address ipToSearch(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
-	liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ipToSearch);
+	liveDev = pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(ipToSearch);
 	PTF_ASSERT_NOT_NULL(liveDev);
 	PTF_ASSERT_TRUE(liveDev->open());
 	DeviceTeardown devTearDown(liveDev);
@@ -951,18 +950,16 @@ PTF_TEST_CASE(TestRemoteCapture)
 	PTF_ASSERT_NOT_NULL(rpcapdInitializer.getHandle());
 
 	pcpp::IPv4Address remoteDeviceIPAddr(remoteDeviceIP);
-	pcpp::PcapRemoteDeviceList* remoteDevices =
-	    pcpp::PcapRemoteDeviceList::getRemoteDeviceList(remoteDeviceIPAddr, remoteDevicePort);
+	auto remoteDevices = pcpp::PcapRemoteDeviceList::createRemoteDeviceList(remoteDeviceIPAddr, remoteDevicePort);
 	PTF_ASSERT_NOT_NULL(remoteDevices);
-	for (pcpp::PcapRemoteDeviceList::RemoteDeviceListIterator remoteDevIter = remoteDevices->begin();
-	     remoteDevIter != remoteDevices->end(); remoteDevIter++)
+	for (auto const remoteDevicePtr : *remoteDevices)
 	{
-		PTF_ASSERT_FALSE((*remoteDevIter)->getName().empty());
+		PTF_ASSERT_FALSE(remoteDevicePtr->getName().empty());
 	}
 	PTF_ASSERT_EQUAL(remoteDevices->getRemoteMachineIpAddress().toString(), remoteDeviceIP);
 	PTF_ASSERT_EQUAL(remoteDevices->getRemoteMachinePort(), remoteDevicePort);
 
-	pcpp::PcapRemoteDevice* remoteDevice = remoteDevices->getRemoteDeviceByIP(remoteDeviceIPAddr);
+	pcpp::PcapRemoteDevice* remoteDevice = remoteDevices->getDeviceByIp(remoteDeviceIPAddr);
 	PTF_ASSERT_NOT_NULL(remoteDevice);
 	PTF_ASSERT_EQUAL(remoteDevice->getDeviceType(), pcpp::PcapLiveDevice::RemoteDevice, enum);
 	PTF_ASSERT_EQUAL(remoteDevice->getMtu(), 0);
@@ -1028,8 +1025,6 @@ PTF_TEST_CASE(TestRemoteCapture)
 	PTF_ASSERT_NOT_NULL(remoteDeviceCloned);
 	PTF_ASSERT_NOT_NULL(dynamic_cast<pcpp::PcapRemoteDevice*>(remoteDeviceCloned));
 
-	delete remoteDevices;
-
 	// the device object is already deleted, cannot close it
 	devTeardown.cancelTeardown();
 #else
diff --git a/Tests/Pcap++Test/Tests/PfRingTests.cpp b/Tests/Pcap++Test/Tests/PfRingTests.cpp
index aa97ac748..b5385bfa3 100644
--- a/Tests/Pcap++Test/Tests/PfRingTests.cpp
+++ b/Tests/Pcap++Test/Tests/PfRingTests.cpp
@@ -200,12 +200,12 @@ PTF_TEST_CASE(TestPfRingDevice)
 #ifdef USE_PF_RING
 
 	pcpp::PfRingDeviceList& devList = pcpp::PfRingDeviceList::getInstance();
-	PTF_ASSERT_GREATER_THAN(devList.getPfRingDevicesList().size(), 0);
+	PTF_ASSERT_GREATER_THAN(devList.size(), 0);
 	PTF_ASSERT_NOT_EQUAL(devList.getPfRingVersion(), "");
-	pcpp::PcapLiveDevice* pcapLiveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* pcapLiveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(pcapLiveDev);
-	pcpp::PfRingDevice* dev = devList.getPfRingDeviceByName(pcapLiveDev->getName());
+	pcpp::PfRingDevice* dev = devList.getDeviceByName(pcapLiveDev->getName());
 
 	PTF_ASSERT_NOT_NULL(dev);
 	PTF_ASSERT_GREATER_THAN(dev->getInterfaceIndex(), 0);
@@ -252,10 +252,10 @@ PTF_TEST_CASE(TestPfRingDeviceSingleChannel)
 #ifdef USE_PF_RING
 
 	pcpp::PfRingDeviceList& devList = pcpp::PfRingDeviceList::getInstance();
-	pcpp::PcapLiveDevice* pcapLiveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* pcapLiveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(pcapLiveDev);
-	pcpp::PfRingDevice* dev = devList.getPfRingDeviceByName(pcapLiveDev->getName());
+	pcpp::PfRingDevice* dev = devList.getDeviceByName(pcapLiveDev->getName());
 	PTF_ASSERT_NOT_NULL(dev);
 
 	PfRingPacketData packetData;
@@ -293,10 +293,10 @@ PTF_TEST_CASE(TestPfRingDeviceMultiThread)
 {
 #ifdef USE_PF_RING
 	pcpp::PfRingDeviceList& devList = pcpp::PfRingDeviceList::getInstance();
-	pcpp::PcapLiveDevice* pcapLiveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* pcapLiveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(pcapLiveDev);
-	pcpp::PfRingDevice* dev = devList.getPfRingDeviceByName(pcapLiveDev->getName());
+	pcpp::PfRingDevice* dev = devList.getDeviceByName(pcapLiveDev->getName());
 	PTF_ASSERT_NOT_NULL(dev);
 
 	uint8_t numOfChannels = dev->getTotalNumOfRxChannels();
@@ -434,10 +434,10 @@ PTF_TEST_CASE(TestPfRingSendPacket)
 {
 #ifdef USE_PF_RING
 	pcpp::PfRingDeviceList& devList = pcpp::PfRingDeviceList::getInstance();
-	pcpp::PcapLiveDevice* pcapLiveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* pcapLiveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(pcapLiveDev);
-	pcpp::PfRingDevice* dev = devList.getPfRingDeviceByName(pcapLiveDev->getName());
+	pcpp::PfRingDevice* dev = devList.getDeviceByName(pcapLiveDev->getName());
 	PTF_ASSERT_NOT_NULL(dev);
 	PTF_ASSERT_TRUE(dev->open());
 	DeviceTeardown devTeardown(dev);
@@ -499,10 +499,10 @@ PTF_TEST_CASE(TestPfRingSendPackets)
 {
 #ifdef USE_PF_RING
 	pcpp::PfRingDeviceList& devList = pcpp::PfRingDeviceList::getInstance();
-	pcpp::PcapLiveDevice* pcapLiveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* pcapLiveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(pcapLiveDev);
-	pcpp::PfRingDevice* dev = devList.getPfRingDeviceByName(pcapLiveDev->getName());
+	pcpp::PfRingDevice* dev = devList.getDeviceByName(pcapLiveDev->getName());
 	PTF_ASSERT_NOT_NULL(dev);
 	PTF_ASSERT_TRUE(dev->open());
 	DeviceTeardown devTeardown(dev);
@@ -542,10 +542,10 @@ PTF_TEST_CASE(TestPfRingFilters)
 {
 #ifdef USE_PF_RING
 	pcpp::PfRingDeviceList& devList = pcpp::PfRingDeviceList::getInstance();
-	pcpp::PcapLiveDevice* pcapLiveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	pcpp::PcapLiveDevice* pcapLiveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	PTF_ASSERT_NOT_NULL(pcapLiveDev);
-	pcpp::PfRingDevice* dev = devList.getPfRingDeviceByName(pcapLiveDev->getName());
+	pcpp::PfRingDevice* dev = devList.getDeviceByName(pcapLiveDev->getName());
 	PTF_ASSERT_NOT_NULL(dev);
 
 	PTF_ASSERT_FALSE(dev->isFilterCurrentlySet());
diff --git a/Tests/Pcap++Test/Tests/XdpTests.cpp b/Tests/Pcap++Test/Tests/XdpTests.cpp
index 13676c387..200fe4bbd 100644
--- a/Tests/Pcap++Test/Tests/XdpTests.cpp
+++ b/Tests/Pcap++Test/Tests/XdpTests.cpp
@@ -35,8 +35,8 @@ bool assertConfig(const pcpp::XdpDevice::XdpDeviceConfiguration* config,
 
 std::string getDeviceName()
 {
-	auto pcapLiveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(
-	    PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
+	auto pcapLiveDev =
+	    pcpp::PcapLiveDeviceList::getInstance().getDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str());
 	if (pcapLiveDev)
 	{
 		return pcapLiveDev->getName();
diff --git a/Tests/Pcap++Test/main.cpp b/Tests/Pcap++Test/main.cpp
index 784a9e0d6..821bab085 100644
--- a/Tests/Pcap++Test/main.cpp
+++ b/Tests/Pcap++Test/main.cpp
@@ -227,6 +227,7 @@ int main(int argc, char* argv[])
 	PTF_RUN_TEST(TestSolarisSnoopFileRead, "no_network;pcap;snoop");
 	PTF_RUN_TEST(TestPcapFileWriterDeviceDestructor, "no_network;pcap");
 
+	PTF_RUN_TEST(TestDeviceListBase, "no_network");
 	PTF_RUN_TEST(TestPcapLiveDeviceList, "no_network;live_device;skip_mem_leak_check");
 	PTF_RUN_TEST(TestPcapLiveDeviceListSearch, "live_device");
 	PTF_RUN_TEST(TestPcapLiveDevice, "live_device");
diff --git a/cppcheckSuppressions.txt b/cppcheckSuppressions.txt
index 771a24fba..9d4e3a876 100644
--- a/cppcheckSuppressions.txt
+++ b/cppcheckSuppressions.txt
@@ -1,5 +1,6 @@
 *:3rdParty/*
 
+checkersReport:*
 ConfigurationNotChecked:*
 ctuOneDefinitionRuleViolation:Examples/*
 missingInclude:*