Structuring SDL Programs

Removing UI Components from a std::vector in SDL/C++

How would I remove a component from the UI manager's std::vector?

Abstract art representing computer programming

Removing components dynamically from a std::vector, especially one containing smart pointers like std::unique_ptr, is a common requirement in UIs (e.g., closing a panel, deleting an item). The Standard Library provides mechanisms to do this efficiently.

The Erase-Remove Idiom

The most common and efficient way to remove elements meeting a certain condition from a std::vector is the erase-remove idiom. It works in two steps:

  1. std::remove() (or std::remove_if()): This algorithm iterates through the vector, moving all elements not meeting the removal condition to the beginning of the vector. It returns an iterator pointing to the start of the "removed" elements (which are now in a valid but unspecified state). It doesn't actually change the vector's size or destroy elements.
  2. vector::erase(): This member function is then called with the iterator range returned by std::remove() up to the vector's end(). This actually erases the elements from the vector, adjusts its size, and ensures destructors are called (which is important for std::unique_ptr).

Example: Removing a Specific Component

Let's say our UI class stores components in std::vector<std::unique_ptr<Rectangle>> Rectangles; and we have a pointer ComponentToRemove (which is a Rectangle*) to the component we want to delete.

// UI.h
// ... inside the UI class ...
#include <vector>
#include <memory>
#include <algorithm> // For std::remove_if
#include "Rectangle.h"

class UI {
  // ... Constructor, Render, HandleEvent ...

public:
  void RemoveComponent(Rectangle* ComponentToRemove) {
    auto IsComponentToRemove = 
      [&](const std::unique_ptr<Rectangle>& ptr) {
        return ptr.get() == ComponentToRemove;
      };

    // 1. Move the element(s) to remove to the end
    auto IterToRemove = std::remove_if( 
      Rectangles.begin(), Rectangles.end(),
      IsComponentToRemove
    );

    // 2. Erase the "removed" elements
    // This calls the destructor for the unique_ptr,
    // which deletes the Rectangle object.
    Rectangles.erase(IterToRemove, Rectangles.end());
  }

private:
  std::vector<std::unique_ptr<Rectangle>> Rectangles;
};

In this example:

  1. We define a lambda function IsComponentToRemove that captures the raw pointer ComponentToRemove. This lambda checks if the raw pointer managed by a std::unique_ptr in the vector matches the one we want to remove.
  2. std::remove_if iterates through Rectangles, using our lambda. It shifts all elements not matching ComponentToRemove towards the front. IterToRemove will point to the first element that does match (or Rectangles.end() if none match).
  3. Rectangles.erase() removes the range from IterToRemove to the end. Because we're using std::unique_ptr, erasing the smart pointer automatically calls delete on the managed Rectangle object, ensuring proper cleanup.

Important Considerations

  • Identifying the Component: The example uses a raw pointer to identify the component. You might also use a unique ID, a specific property, or other criteria within the lambda passed to std::remove_if().
  • Performance: While erase-remove is generally efficient for vectors, removing elements requires shifting subsequent elements, which can be costly for very large vectors if removals happen frequently near the beginning. For performance-critical scenarios with frequent additions/removals, other containers like std::list or std::deque might be considered, though they have different performance trade-offs.
  • Iterators: Be careful if you are iterating over the vector while also potentially removing elements from it. The erase-remove idiom is typically done outside the main iteration loop or requires careful iterator handling.

Note: Managing the lifecycle of objects, including dynamic addition and removal, involves several related concepts. We cover these topics, including different container choices and memory management strategies, in more detail later in the course.

This Question is from the Lesson:

Structuring SDL Programs

Discover how to organize SDL components using manager classes, inheritance, and polymorphism for cleaner code.

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

Structuring SDL Programs

Discover how to organize SDL components using manager classes, inheritance, and polymorphism for cleaner code.

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

This course includes:

  • 110 Lessons
  • 92% Positive Reviews
  • Regularly Updated
  • Help and FAQs
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2025 - All Rights Reserved