layers: Improve DescriptorSet cleanup

Create private helper function InvalidateBoundCmdBuffers() within the
DescriptorSet class to unify invalidate cases due to set being updated
or freed.

Add a destructor for DescriptorSet to make sure that no bound cmd buffers
hang on to deleted set references.
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 780d27d..3e5360b 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -3387,15 +3387,6 @@
     }
     return skip_call;
 }
-static void invalidateBoundCmdBuffers(layer_data *dev_data, cvdescriptorset::DescriptorSet *pSet) {
-    // Flag any CBs this set is bound to as INVALID and remove set binding
-    for (auto cb_node : pSet->GetBoundCmdBuffers()) {
-        cb_node->state = CB_INVALID;
-        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
-            cb_node->lastBound[i].uniqueBoundSets.erase(pSet);
-        }
-    }
-}
 // update DS mappings based on write and copy update arrays
 static bool dsUpdate(layer_data *my_data, VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pWDS,
                      uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pCDS) {
@@ -3505,7 +3496,6 @@
 
 // Free the descriptor set, remove it from setMap and invalidate any cmd buffers that it was bound to
 static void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
-    invalidateBoundCmdBuffers(dev_data, descriptor_set);
     dev_data->setMap.erase(descriptor_set->GetSet());
     delete descriptor_set;
 }
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index 437dcdc..1d9eed6 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -324,6 +324,15 @@
         }
     }
 }
+cvdescriptorset::DescriptorSet::~DescriptorSet() {
+    InvalidateBoundCmdBuffers();
+    // Remove link to any cmd buffers
+    for (auto cb : bound_cmd_buffers_) {
+        for (uint32_t i=0; i<VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
+            cb->lastBound[i].uniqueBoundSets.erase(this);
+        }
+    }
+}
 // Is this sets underlying layout compatible with passed in layout according to "Pipeline Layout Compatibility" in spec?
 bool cvdescriptorset::DescriptorSet::IsCompatible(const DescriptorSetLayout *layout, std::string *error) const {
     return layout->IsCompatible(p_layout_, error);
@@ -452,6 +461,12 @@
     p_layout_->FillBindingSet(&binding_set);
     return GetStorageUpdates(binding_set, buffer_set, image_set);
 }
+// Set is being deleted or updates so invalidate all bound cmd buffers
+void cvdescriptorset::DescriptorSet::InvalidateBoundCmdBuffers() {
+    for (auto cb_node : bound_cmd_buffers_) {
+        cb_node->state = CB_INVALID;
+    }
+}
 // Perform write update in given update struct
 //  If an error occurs, return false and fill in details in error_msg string
 bool cvdescriptorset::DescriptorSet::WriteUpdate(debug_report_data *report_data, const VkWriteDescriptorSet *update,
@@ -514,10 +529,7 @@
     if (num_updates != 0) {
         some_update_ = true;
     }
-    // Invalidate any bound command buffers
-    for (auto cb_node : bound_cmd_buffers_) {
-        cb_node->state = CB_INVALID;
-    }
+    InvalidateBoundCmdBuffers();
     return true;
 }
 // Copy update
@@ -595,10 +607,7 @@
     if (num_updates != 0) {
         some_update_ = true;
     }
-    // Invalidate any bound command buffers
-    for (auto cb_node : bound_cmd_buffers_) {
-        cb_node->state = CB_INVALID;
-    }
+    InvalidateBoundCmdBuffers();
     return true;
 }
 cvdescriptorset::SamplerDescriptor::SamplerDescriptor(
diff --git a/layers/descriptor_sets.h b/layers/descriptor_sets.h
index 5b358d6..5abe45f 100644
--- a/layers/descriptor_sets.h
+++ b/layers/descriptor_sets.h
@@ -290,7 +290,7 @@
                   const std::unordered_map<VkImageView, VkImageViewCreateInfo> *, const std::unordered_map<VkImage, IMAGE_NODE> *,
                   const std::unordered_map<VkImage, VkSwapchainKHR> *,
                   const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *);
-    ~DescriptorSet(){};
+    ~DescriptorSet();
     // A number of common Get* functions that return data based on layout from which this set was created
     uint32_t GetTotalDescriptorCount() const { return p_layout_ ? p_layout_->GetTotalDescriptorCount() : 0; };
     uint32_t GetDynamicDescriptorCount() const { return p_layout_ ? p_layout_->GetDynamicDescriptorCount() : 0; };
@@ -351,6 +351,8 @@
 
   private:
     bool ValidateUpdate(const VkWriteDescriptorSet *, const uint32_t, std::string *) const;
+    // Private helper to set all bound cmd buffers to INVALID state
+    void InvalidateBoundCmdBuffers();
     bool some_update_; // has any part of the set ever been updated?
     VkDescriptorSet set_;
     uint32_t descriptor_count_; // Count of all descriptors in this set