diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
index 576856a..dbdc78e 100644
--- a/src/libcamera/camera_manager.cpp
+++ b/src/libcamera/camera_manager.cpp
@@ -63,7 +63,6 @@ private:
 	bool initialized_;
 	int status_;
 
-	std::vector<std::shared_ptr<PipelineHandler>> pipes_;
 	std::unique_ptr<DeviceEnumerator> enumerator_;
 
 	IPAManager ipaManager_;
@@ -144,7 +143,6 @@ int CameraManager::Private::init()
 			LOG(Camera, Debug)
 				<< "Pipeline handler \"" << factory->name()
 				<< "\" matched";
-			pipes_.push_back(std::move(pipe));
 		}
 	}
 
@@ -158,11 +156,9 @@ void CameraManager::Private::cleanup()
 	/* TODO: unregister hot-plug callback here */
 
 	/*
-	 * Release all references to cameras and pipeline handlers to ensure
-	 * they all get destroyed before the device enumerator deletes the
-	 * media devices.
+	 * Release all references to cameras to ensure they all get destroyed
+	 * before the device enumerator deletes the media devices.
 	 */
-	pipes_.clear();
 	cameras_.clear();
 
 	enumerator_.reset(nullptr);
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index a0f6b0f..c457be9 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -559,7 +559,21 @@ void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)
  */
 void PipelineHandler::disconnect()
 {
-	for (std::weak_ptr<Camera> ptr : cameras_) {
+	/*
+	 * Each camera holds a reference to its associated pipeline handler
+	 * instance. Hence, when the last camera is dropped, the pipeline
+	 * handler will get destroyed by the last manager_->removeCamera(camera)
+	 * call in the loop below.
+	 *
+	 * This is acceptable as long as we make sure that the code path does not
+	 * access any member of the (already destroyed)pipeline handler instance
+	 * afterwards. Therefore, we move the cameras_ vector to a local temporary
+	 * container to avoid accessing freed memory later i.e. to explicitly run
+	 * cameras_.clear().
+	 */
+	std::vector<std::weak_ptr<Camera>> cameras{ std::move(cameras_) };
+
+	for (std::weak_ptr<Camera> ptr : cameras) {
 		std::shared_ptr<Camera> camera = ptr.lock();
 		if (!camera)
 			continue;
@@ -567,8 +581,6 @@ void PipelineHandler::disconnect()
 		camera->disconnect();
 		manager_->removeCamera(camera.get());
 	}
-
-	cameras_.clear();
 }
 
 /**
