Search code examples
c++c++14stdvectorunordered-map

How can i delete an element from a map into a vector


I'm currently trying for a game project to get rid of a dangling reference when a plane crashes before reaching the terminal it was booked to reach.

I would like to go through <algorithm> functions only to better understand how they work.

At the moment I've tried going through the map that contains all the planes associated with a terminal, comparing it with the list of all the planes and checking if a plane that is in the map is no longer in the vector then delete it from the map to free the associated terminal.

void remove_crashed_aircraft(std::unordered_map<const Aircraft*, size_t>& reserved_terminals, std::vector<std::unique_ptr<Aircraft>>& aircrafts)
{
    auto it = std::all_of(reserved_terminals.begin(), reserved_terminals.end(), 
        [aircrafts](const Aircraft* a1){ return std::find_if(aircrafts.begin(), aircrafts.end(),
            [a1](std::unique_ptr<Aircraft> a2){ return a1==a2.get();});});
    
    reserved_terminals.erase(it);
}

And this is my Aircraft class:

class Aircraft : public GL::Displayable, public GL::DynamicObject
{
private:
    const AircraftType& type;
    const std::string flight_number;
    Point3D pos, speed; // note: the speed should always be normalized to length 'speed'
    WaypointQueue waypoints = {};
    Tower& control;
    bool landing_gear_deployed = false; // is the landing gear deployed?
    bool is_at_terminal        = false;
    int fuel                   = 0;

    // turn the aircraft to arrive at the next waypoint
    // try to facilitate reaching the waypoint after the next by facing the
    // right way to this end, we try to face the point Z on the line spanned by
    // the next two waypoints such that Z's distance to the next waypoint is
    // half our distance so: |w1 - pos| = d and [w1 - w2].normalize() = W and Z
    // = w1 + W*d/2
    void turn_to_waypoint();
    void turn(Point3D direction);

    // select the correct tile in the plane texture (series of 8 sprites facing
    // [North, NW, W, SW, S, SE, E, NE])
    unsigned int get_speed_octant() const;
    // when we arrive at a terminal, signal the tower
    void arrive_at_terminal();
    // deploy and retract landing gear depending on next waypoints
    void operate_landing_gear();
    void add_waypoint(const Waypoint& wp, const bool front);
    bool is_on_ground() const { return pos.z() < DISTANCE_THRESHOLD; }
    float max_speed() const { return is_on_ground() ? type.max_ground_speed : type.max_air_speed; }
    bool is_paused = false;

    Aircraft(const Aircraft&) = delete;
    Aircraft& operator=(const Aircraft&) = delete;

public:
    Aircraft(const AircraftType& type_, const std::string_view& flight_number_, const Point3D& pos_,
             const Point3D& speed_, Tower& control_, int fuel_) :
        GL::Displayable { pos_.x() + pos_.y() },
        type { type_ },
        flight_number { flight_number_ },
        pos { pos_ },
        speed { speed_ },
        control { control_ },
        fuel { fuel_ }
    {
        speed.cap_length(max_speed());
    }

    const std::string& get_flight_num() const { return flight_number; }
    float distance_to(const Point3D& p) const { return pos.distance_to(p); }
    bool is_circling() const 
    {
        if (!has_terminal() && !is_at_terminal)
        {
            return true;
        }
        return false;
    }
    bool has_terminal() const 
    { 
        if (waypoints.empty())
        {
            return false;
        }
        else
        {
            return waypoints.back().type == wp_terminal;
        } 
    }
    bool is_low_on_fuel() const 
    {
        if (fuel<200)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    void display() const override;
    bool move() override;
    void refill(int& fuel_stock);

    friend class Tower;
    friend class AircraftManager;
};

The code of the function generates errors that I can't understand unfortunately.

use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Aircraft; _Dp = std::default_delete<Aircraft>]’

static assertion failed: result type must be constructible from value type of input range

If anyone has an idea of how I can achieve this, I would be very grateful!


Solution

  • First, you have to use std::remove_if, because std::all_of returns bool, not iterator. But std::remove_if does what you want, it removes all instances that match bool predicate.

    Second, your compile errors appear because you pass by value everywhere, so instead of (std::unique_ptr<Aircraft> a2) pass reference (std::unique_ptr<Aircraft> const & a2), instead [aircrafts] and [a1] pass [&aircrafts] and [&a1].

    Third, inner predicate should not just return result of std::find_if (which returns iterator) but return bool, i.e. compare result of find_if to aircrafts.end().

    Speed-wise your algorithm can be optimized if needed, for that you have to convert std::vector to std::unordered_set and then iterate through first map and check containment inside second set. If you don't have too many elements and speed is not of much importance then your algorithm is alright.

    Final working code below:

    void remove_crashed_aircraft(
        std::unordered_map<const Aircraft*, size_t>& reserved_terminals,
        std::vector<std::unique_ptr<Aircraft>>& aircrafts
    ) {
        std::remove_if(reserved_terminals.begin(), reserved_terminals.end(), 
            [&aircrafts](auto const & a1){
                return std::find_if(aircrafts.begin(), aircrafts.end(),
                    [&a1](auto const & a2){ return a1.first == a2.get(); })
                    == aircrafts.end();
            }
        );
    }