diff --git a/code/mission/missionmessage.cpp b/code/mission/missionmessage.cpp index 54efc4aa010..5bd686668ab 100644 --- a/code/mission/missionmessage.cpp +++ b/code/mission/missionmessage.cpp @@ -41,6 +41,8 @@ #include "species_defs/species_defs.h" #include "utils/Random.h" +#include // for std::exchange + bool Allow_generic_backup_messages = false; bool Always_loop_head_anis = false; bool Use_newer_head_ani_suffix = false; @@ -72,14 +74,44 @@ builtin_message::builtin_message(const builtin_message& other) builtin_message& builtin_message::operator=(const builtin_message& other) { - name = other.used_strdup ? vm_strdup(other.name) : other.name; - occurrence_chance = other.occurrence_chance; - max_count = other.max_count; - min_delay = other.min_delay; - priority = other.priority; - timing = other.timing; - fallback = other.fallback; - used_strdup = other.used_strdup; + if (this != &other) + { + const char* new_name = other.used_strdup ? vm_strdup(other.name) : other.name; + if (used_strdup) + vm_free(const_cast(name)); + + name = new_name; + occurrence_chance = other.occurrence_chance; + max_count = other.max_count; + min_delay = other.min_delay; + priority = other.priority; + timing = other.timing; + fallback = other.fallback; + used_strdup = other.used_strdup; + } + return *this; +} + +builtin_message::builtin_message(builtin_message&& other) noexcept + : name(std::exchange(other.name, nullptr)), occurrence_chance(other.occurrence_chance), max_count(other.max_count), min_delay(other.min_delay), priority(other.priority), timing(other.timing), fallback(other.fallback), used_strdup(std::exchange(other.used_strdup, false)) +{} + +builtin_message& builtin_message::operator=(builtin_message&& other) noexcept +{ + if (this != &other) + { + if (used_strdup) + vm_free(const_cast(name)); + + name = std::exchange(other.name, nullptr); + occurrence_chance = other.occurrence_chance; + max_count = other.max_count; + min_delay = other.min_delay; + priority = other.priority; + timing = other.timing; + fallback = other.fallback; + used_strdup = std::exchange(other.used_strdup, false); + } return *this; } diff --git a/code/mission/missionmessage.h b/code/mission/missionmessage.h index e69d224ca67..794a22a00c7 100644 --- a/code/mission/missionmessage.h +++ b/code/mission/missionmessage.h @@ -77,12 +77,13 @@ typedef struct builtin_message { bool used_strdup; builtin_message(const char* _name, int _occurrence_chance, int _max_count, int _min_delay, int _priority, int _timing, int _fallback, bool _used_strdup); - // since we need a destructor, we need the other four special member functions as well + // since we need a destructor, we need the other four special member functions as well; + // all four must handle the conditionally-owned name so they can't be defaulted ~builtin_message(); builtin_message(const builtin_message& other); builtin_message& operator=(const builtin_message& other); - builtin_message(builtin_message&& other) noexcept = default; - builtin_message& operator=(builtin_message&& other) noexcept = default; + builtin_message(builtin_message&& other) noexcept; + builtin_message& operator=(builtin_message&& other) noexcept; } builtin_message; // If these are changed or updated be sure to update the map in scripting/api/libs/mission.cpp and the connected lua enumerations! diff --git a/code/model/modelread.cpp b/code/model/modelread.cpp index 416edf37c15..6714ea0fafc 100644 --- a/code/model/modelread.cpp +++ b/code/model/modelread.cpp @@ -3245,7 +3245,7 @@ int model_load(const char* filename, ship_info* sip, ErrorType error_type, bool if (sip != nullptr) { n_subsystems = sip->n_subsystems; - subsystems = sip->subsystems; + subsystems = sip->subsystems.get(); } num = -1; @@ -6025,6 +6025,11 @@ void parse_glowpoint_table(const char *filename) void glowpoint_init() { + // ship_info and prop_info store indices into glowpoint_bank_overrides + extern bool Ships_inited; + extern bool Props_inited; + Assertion(!Ships_inited && !Props_inited, "glowpoint_init() must be called before ship_init() and prop_init()"); + glowpoint_bank_overrides.clear(); parse_glowpoint_table("glowpoints.tbl"); parse_modular_table(NOX("*-gpo.tbm"), parse_glowpoint_table); diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index f1ef2b8d643..9e7b1e94328 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -1946,7 +1946,6 @@ void model_render_set_glow_points(const polymodel *pm, int objnum) int time = timestamp(); glow_point_bank_override *gpo = nullptr; bool override_all = false; - SCP_unordered_map::iterator gpoi; ship_info *sip = nullptr; ship *shipp = nullptr; @@ -1960,11 +1959,11 @@ void model_render_set_glow_points(const polymodel *pm, int objnum) if ( objp != NULL && objp->type == OBJ_SHIP ) { shipp = &Ships[Objects[objnum].instance]; sip = &Ship_info[shipp->ship_info_index]; - gpoi = sip->glowpoint_bank_override_map.find(-1); + auto gpoi = sip->glowpoint_bank_override_map.find(-1); if (gpoi != sip->glowpoint_bank_override_map.end()) { override_all = true; - gpo = (glow_point_bank_override*)sip->glowpoint_bank_override_map[-1]; + gpo = &glowpoint_bank_overrides[gpoi->second]; } } } @@ -1973,12 +1972,12 @@ void model_render_set_glow_points(const polymodel *pm, int objnum) glow_point_bank *bank = &pm->glow_point_banks[i]; if ( !override_all && sip ) { - gpoi = sip->glowpoint_bank_override_map.find(i); + auto gpoi = sip->glowpoint_bank_override_map.find(i); if ( gpoi != sip->glowpoint_bank_override_map.end() ) { - gpo = (glow_point_bank_override*) sip->glowpoint_bank_override_map[i]; + gpo = &glowpoint_bank_overrides[gpoi->second]; } else { - gpo = NULL; + gpo = nullptr; } } @@ -2013,16 +2012,15 @@ void model_render_glow_points(const polymodel *pm, const polymodel_instance *pmi glow_point_bank_override *gpo = nullptr; bool override_all = false; - SCP_unordered_map::iterator gpoi; ship_info *sip = nullptr; if ( shipp ) { sip = &Ship_info[shipp->ship_info_index]; - gpoi = sip->glowpoint_bank_override_map.find(-1); + auto gpoi = sip->glowpoint_bank_override_map.find(-1); if(gpoi != sip->glowpoint_bank_override_map.end()) { override_all = true; - gpo = (glow_point_bank_override*) sip->glowpoint_bank_override_map[-1]; + gpo = &glowpoint_bank_overrides[gpoi->second]; } } @@ -2030,9 +2028,9 @@ void model_render_glow_points(const polymodel *pm, const polymodel_instance *pmi glow_point_bank *bank = &pm->glow_point_banks[i]; if(!override_all && sip) { - gpoi = sip->glowpoint_bank_override_map.find(i); + auto gpoi = sip->glowpoint_bank_override_map.find(i); if(gpoi != sip->glowpoint_bank_override_map.end()) { - gpo = (glow_point_bank_override*) sip->glowpoint_bank_override_map[i]; + gpo = &glowpoint_bank_overrides[gpoi->second]; } else { gpo = nullptr; } diff --git a/code/prop/prop.cpp b/code/prop/prop.cpp index 41331d3b92a..20eccc5e1bc 100644 --- a/code/prop/prop.cpp +++ b/code/prop/prop.cpp @@ -547,7 +547,7 @@ int prop_create(const matrix* orient, const vec3d* pos, int prop_type, const cha auto gpoi = pip->glowpoint_bank_override_map.find(bank); if (gpoi != pip->glowpoint_bank_override_map.end()) { - gpo = (glow_point_bank_override*)pip->glowpoint_bank_override_map[bank]; + gpo = &glowpoint_bank_overrides[gpoi->second]; } if (gpo) { @@ -637,7 +637,7 @@ static void prop_model_change(int n, int prop_type) auto gpoi = sip->glowpoint_bank_override_map.find(bank); if (gpoi != sip->glowpoint_bank_override_map.end()) { - gpo = (glow_point_bank_override*)sip->glowpoint_bank_override_map[bank]; + gpo = &glowpoint_bank_overrides[gpoi->second]; } if (gpo) { diff --git a/code/prop/prop.h b/code/prop/prop.h index 39a62962fb6..96ef53a3e05 100644 --- a/code/prop/prop.h +++ b/code/prop/prop.h @@ -19,7 +19,7 @@ typedef struct prop_info { int model_num = -1; // The model number of the loaded POF int num_detail_levels; // Detail levels of the model int detail_distance[MAX_PROP_DETAIL_LEVELS]; // distance to change detail levels at - SCP_unordered_map glowpoint_bank_override_map; // Glow point bank overrides currently unused + SCP_unordered_map glowpoint_bank_override_map; // Glow point bank overrides currently unused; values index glowpoint_bank_overrides flagset flags; // Info flags SCP_map custom_data; // Custom data for this prop SCP_vector custom_strings; // Custom strings for this prop diff --git a/code/ship/ship.cpp b/code/ship/ship.cpp index a18ada69b4c..f665b960494 100644 --- a/code/ship/ship.cpp +++ b/code/ship/ship.cpp @@ -1154,18 +1154,10 @@ void ship_info::clone(const ship_info& other) generic_debris_spew_num = other.generic_debris_spew_num; if ( other.n_subsystems > 0 ) { - if( n_subsystems < 1 ) { - subsystems = new model_subsystem[other.n_subsystems]; - } else { - delete[] subsystems; - subsystems = new model_subsystem[other.n_subsystems]; - } - - Assert(subsystems != nullptr); - - for ( int i = 0; i < other.n_subsystems; i++ ) { - subsystems[i] = other.subsystems[i]; - } + subsystems.reset(new model_subsystem[other.n_subsystems]); + std::copy(other.subsystems.get(), other.subsystems.get() + other.n_subsystems, subsystems.get()); + } else { + subsystems.reset(); } n_subsystems = other.n_subsystems; @@ -1403,375 +1395,6 @@ void ship_info::clone(const ship_info& other) default_subsys_death_effect = other.default_subsys_death_effect; } -void ship_info::move(ship_info&& other) -{ - std::swap(name, other.name); - std::swap(display_name, other.display_name); - std::swap(short_name, other.short_name); - species = other.species; - class_type = other.class_type; - - std::swap(type_str, other.type_str); - std::swap(maneuverability_str, other.maneuverability_str); - std::swap(armor_str, other.armor_str); - std::swap(manufacturer_str, other.manufacturer_str); - std::swap(desc, other.desc); - std::swap(tech_desc, other.tech_desc); - - std::swap(tech_title, other.tech_title); - - std::swap(ship_length, other.ship_length); - std::swap(gun_mounts, other.gun_mounts); - std::swap(missile_banks, other.missile_banks); - - std::swap(cockpit_pof_file, other.cockpit_pof_file); - std::swap(cockpit_offset, other.cockpit_offset); - cockpit_sway_val = other.cockpit_sway_val; - std::swap(pof_file, other.pof_file); - std::swap(pof_file_hud, other.pof_file_hud); - std::swap(pof_file_tech, other.pof_file_tech); - num_detail_levels = other.num_detail_levels; - std::swap(detail_distance, other.detail_distance); - collision_lod = other.collision_lod; - - cockpit_model_num = other.cockpit_model_num; - model_num = other.model_num; - model_num_hud = other.model_num_hud; - - hud_target_lod = other.hud_target_lod; - density = other.density; - damp = other.damp; - rotdamp = other.rotdamp; - delta_bank_const = other.delta_bank_const; - std::swap(max_vel, other.max_vel); - std::swap(min_vel, other.min_vel); - std::swap(max_rotvel, other.max_rotvel); - std::swap(rotation_time, other.rotation_time); - srotation_time = other.srotation_time; - max_rear_vel = other.max_rear_vel; - forward_accel = other.forward_accel; - forward_decel = other.forward_decel; - slide_accel = other.slide_accel; - slide_decel = other.slide_decel; - gravity_const = other.gravity_const; - dying_gravity_const = other.dying_gravity_const; - - warpin_params_index = other.warpin_params_index; - warpout_params_index = other.warpout_params_index; - - flags = other.flags; - ai_class = other.ai_class; - max_speed = other.max_speed; - min_speed = other.min_speed; - max_accel = other.max_accel; - - collision_damage_type_idx = other.collision_damage_type_idx; - std::swap(collision_physics, other.collision_physics); - - std::swap(shockwave, other.shockwave); - explosion_propagates = other.explosion_propagates; - explosion_splits_ship = other.explosion_splits_ship; - big_exp_visual_rad = other.big_exp_visual_rad; - prop_exp_rad_mult = other.prop_exp_rad_mult; - death_roll_r_mult = other.death_roll_r_mult; - death_fx_r_mult = other.death_fx_r_mult; - death_roll_time_mult = other.death_roll_time_mult; - death_roll_rotation_mult = other.death_roll_rotation_mult; - death_roll_xrotation_cap = other.death_roll_xrotation_cap; - death_roll_yrotation_cap = other.death_roll_yrotation_cap; - death_roll_zrotation_cap = other.death_roll_zrotation_cap; - death_roll_base_time = other.death_roll_base_time; - death_fx_count = other.death_fx_count; - shockwave_count = other.shockwave_count; - std::swap(explosion_bitmap_anims, other.explosion_bitmap_anims); - skip_deathroll_chance = other.skip_deathroll_chance; - - std::swap(impact_spew, other.impact_spew); - std::swap(damage_spew, other.damage_spew); - std::swap(death_roll_exp_particles, other.death_roll_exp_particles); - std::swap(pre_death_exp_particles, other.pre_death_exp_particles); - std::swap(propagating_exp_particles, other.propagating_exp_particles); - std::swap(split_particles, other.split_particles); - std::swap(knossos_end_particles, other.knossos_end_particles); - std::swap(regular_end_particles, other.regular_end_particles); - std::swap(debris_flame_particles, other.debris_flame_particles); - std::swap(shrapnel_flame_particles, other.shrapnel_flame_particles); - std::swap(debris_end_particles, other.debris_end_particles); - std::swap(shrapnel_end_particles, other.shrapnel_end_particles); - std::swap(default_subsys_debris_flame_particles, other.default_subsys_debris_flame_particles); - std::swap(default_subsys_shrapnel_flame_particles, other.default_subsys_shrapnel_flame_particles); - - debris_min_lifetime = other.debris_min_lifetime; - debris_max_lifetime = other.debris_max_lifetime; - debris_min_speed = other.debris_min_speed; - debris_max_speed = other.debris_max_speed; - debris_min_rotspeed = other.debris_min_rotspeed; - debris_max_rotspeed = other.debris_max_rotspeed; - debris_damage_type_idx = other.debris_damage_type_idx; - debris_min_hitpoints = other.debris_min_hitpoints; - debris_max_hitpoints = other.debris_max_hitpoints; - debris_hitpoints_radius_multi = other.debris_hitpoints_radius_multi; - debris_damage_mult = other.debris_damage_mult; - debris_arc_percent = other.debris_arc_percent; - debris_gravity_const = other.debris_gravity_const; - debris_density = other.debris_density; - debris_ambient_sound = other.debris_ambient_sound; - debris_collision_sound_light = other.debris_collision_sound_light; - debris_collision_sound_heavy = other.debris_collision_sound_heavy; - debris_explosion_sound = other.debris_explosion_sound; - strcpy_s(generic_debris_pof_file, other.generic_debris_pof_file); - generic_debris_model_num = other.generic_debris_model_num; - generic_debris_num_submodels = other.generic_debris_num_submodels; - generic_debris_spew_num = other.generic_debris_spew_num; - - std::swap(subsystems, other.subsystems); - std::swap(n_subsystems, other.n_subsystems); - - power_output = other.power_output; - max_overclocked_speed = other.max_overclocked_speed; - max_weapon_reserve = other.max_weapon_reserve; - max_shield_regen_per_second = other.max_shield_regen_per_second; - shield_regen_hit_delay = other.shield_regen_hit_delay; - max_weapon_regen_per_second = other.max_weapon_regen_per_second; - - shield_weap_amount = other.shield_weap_amount; - shield_weap_efficiency = other.shield_weap_efficiency; - shield_weap_speed = other.shield_weap_speed; - weap_shield_amount = other.weap_shield_amount; - weap_shield_efficiency = other.weap_shield_efficiency; - weap_shield_speed = other.weap_shield_speed; - - std::swap(afterburner_max_vel, other.afterburner_max_vel); - afterburner_forward_accel = other.afterburner_forward_accel; - afterburner_fuel_capacity = other.afterburner_fuel_capacity; - afterburner_burn_rate = other.afterburner_burn_rate; - afterburner_recover_rate = other.afterburner_recover_rate; - afterburner_max_reverse_vel = other.afterburner_max_reverse_vel; - afterburner_reverse_accel = other.afterburner_reverse_accel; - afterburner_min_start_fuel = other.afterburner_min_start_fuel; - afterburner_min_fuel_to_burn = other.afterburner_min_fuel_to_burn; - afterburner_cooldown_time = other.afterburner_cooldown_time; - - cmeasure_type = other.cmeasure_type; - cmeasure_max = other.cmeasure_max; - - num_primary_banks = other.num_primary_banks; - std::swap(primary_bank_weapons, other.primary_bank_weapons); - std::swap(primary_bank_ammo_capacity, other.primary_bank_ammo_capacity); - - num_secondary_banks = other.num_secondary_banks; - std::swap(secondary_bank_weapons, other.secondary_bank_weapons); - std::swap(secondary_bank_ammo_capacity, other.secondary_bank_ammo_capacity); - - std::swap(draw_primary_models, other.draw_primary_models); - std::swap(draw_secondary_models, other.draw_secondary_models); - weapon_model_draw_distance = other.weapon_model_draw_distance; - - max_hull_strength = other.max_hull_strength; - ship_recoil_modifier = other.ship_recoil_modifier; - ship_shudder_modifier = other.ship_shudder_modifier; - - for (int i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++) { - std::swap(dyn_firing_patterns_allowed[i], other.dyn_firing_patterns_allowed[i]); - } - - max_shield_strength = other.max_shield_strength; - max_shield_recharge = other.max_shield_recharge; - auto_shield_spread = other.auto_shield_spread; - auto_shield_spread_bypass = other.auto_shield_spread_bypass; - auto_shield_spread_from_lod = other.auto_shield_spread_from_lod; - auto_shield_spread_min_span = other.auto_shield_spread_min_span; - max_shield_impact_effect_radius = other.max_shield_impact_effect_radius; - - std::swap(shield_point_augment_ctrls, other.shield_point_augment_ctrls); - - hull_repair_rate = other.hull_repair_rate; - subsys_repair_rate = other.subsys_repair_rate; - - hull_repair_max = other.hull_repair_max; - subsys_repair_max = other.subsys_repair_max; - - sup_hull_repair_rate = other.sup_hull_repair_rate; - sup_shield_repair_rate = other.sup_shield_repair_rate; - sup_subsys_repair_rate = other.sup_subsys_repair_rate; - - std::swap(closeup_pos, other.closeup_pos); - closeup_zoom = other.closeup_zoom; - std::swap(icon_closeup_pos, other.icon_closeup_pos); - icon_closeup_zoom = other.icon_closeup_zoom; - - std::swap(closeup_pos_targetbox, other.closeup_pos_targetbox); - closeup_zoom_targetbox = other.closeup_zoom_targetbox; - - std::swap(chase_view_offset, other.chase_view_offset); - chase_view_rigidity = other.chase_view_rigidity; - - std::swap(allowed_weapons, other.allowed_weapons); - - std::swap(restricted_loadout_flag, other.restricted_loadout_flag); - std::swap(allowed_bank_restricted_weapons, other.allowed_bank_restricted_weapons); - - shield_icon_index = other.shield_icon_index; - std::swap(icon_filename, other.icon_filename); - model_icon_angles = other.model_icon_angles; - std::swap(anim_filename, other.anim_filename); - std::swap(overhead_filename, other.overhead_filename); - selection_effect = other.selection_effect; - fs2_effect_grid_color = other.fs2_effect_grid_color; - fs2_effect_scanline_color = other.fs2_effect_scanline_color; - fs2_effect_grid_density = other.fs2_effect_grid_density; - fs2_effect_wireframe_color = other.fs2_effect_wireframe_color; - - wingmen_status_dot_override = other.wingmen_status_dot_override; - - bii_index_ship = other.bii_index_ship; - bii_index_ship_with_cargo = other.bii_index_ship_with_cargo; - bii_index_wing = other.bii_index_wing; - bii_index_wing_with_cargo = other.bii_index_wing_with_cargo; - - score = other.score; - - scan_time = other.scan_time; - scan_range_normal = other.scan_range_normal; - scan_range_capital = other.scan_range_capital; - scanning_time_multiplier = other.scanning_time_multiplier; - scanning_range_multiplier = other.scanning_range_multiplier; - - ask_help_shield_percent = other.ask_help_shield_percent; - ask_help_hull_percent = other.ask_help_hull_percent; - - std::swap(ct_info, other.ct_info); - ct_count = other.ct_count; - - std::swap(shield_color, other.shield_color); - - uses_team_colors = other.uses_team_colors; - std::swap(default_team_name, other.default_team_name); - - std::swap(afterburner_trail, other.afterburner_trail); - afterburner_trail_tex_stretch = other.afterburner_trail_tex_stretch; - afterburner_trail_width_factor = other.afterburner_trail_width_factor; - afterburner_trail_alpha_factor = other.afterburner_trail_alpha_factor; - afterburner_trail_alpha_end_factor = other.afterburner_trail_alpha_end_factor; - afterburner_trail_alpha_decay_exponent = other.afterburner_trail_alpha_decay_exponent; - afterburner_trail_life = other.afterburner_trail_life; - afterburner_trail_faded_out_sections = other.afterburner_trail_faded_out_sections; - afterburner_trail_spread = other.afterburner_trail_spread; - - std::swap(normal_thruster_particles, other.normal_thruster_particles); - std::swap(afterburner_thruster_particles, other.afterburner_thruster_particles); - - std::swap(thruster_flame_info, other.thruster_flame_info); - std::swap(thruster_glow_info, other.thruster_glow_info); - std::swap(thruster_secondary_glow_info, other.thruster_secondary_glow_info); - std::swap(thruster_tertiary_glow_info, other.thruster_tertiary_glow_info); - std::swap(thruster_distortion_info, other.thruster_distortion_info); - - thruster01_glow_rad_factor = other.thruster01_glow_rad_factor; - thruster02_glow_rad_factor = other.thruster02_glow_rad_factor; - thruster03_glow_rad_factor = other.thruster03_glow_rad_factor; - thruster02_glow_len_factor = other.thruster02_glow_len_factor; - thruster_dist_rad_factor = other.thruster_dist_rad_factor; - thruster_dist_len_factor = other.thruster_dist_len_factor; - thruster_glow_noise_mult = other.thruster_glow_noise_mult; - - draw_distortion = other.draw_distortion; - - std::swap(replacement_textures, other.replacement_textures); - - armor_type_idx = other.armor_type_idx; - shield_armor_type_idx = other.shield_armor_type_idx; - - can_glide = other.can_glide; - glide_cap = other.glide_cap; - glide_dynamic_cap = other.glide_dynamic_cap; - glide_accel_mult = other.glide_accel_mult; - use_newtonian_damp = other.use_newtonian_damp; - newtonian_damp_override = other.newtonian_damp_override; - - autoaim_fov = other.autoaim_fov; - for (int i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++) { - bank_autoaim_fov[i] = other.bank_autoaim_fov[i]; - } - autoaim_lock_snd = other.autoaim_lock_snd; - autoaim_lost_snd = other.autoaim_lost_snd; - - aims_at_flight_cursor = other.aims_at_flight_cursor; - aims_at_flight_cursor_secondary = other.aims_at_flight_cursor_secondary; - flight_cursor_aim_extent = other.flight_cursor_aim_extent; - - topdown_offset_def = other.topdown_offset_def; - std::swap(topdown_offset, other.topdown_offset); - - engine_snd = other.engine_snd; - min_engine_vol = other.min_engine_vol; - glide_start_snd = other.glide_start_snd; - glide_end_snd = other.glide_end_snd; - flyby_snd = other.flyby_snd; - - std::swap(ship_sounds, other.ship_sounds); - - std::swap(custom_data, other.custom_data); - - std::swap(custom_strings, other.custom_strings); - - std::swap(rcs_thrusters, other.rcs_thrusters); - - radar_image_2d_idx = other.radar_image_2d_idx; - radar_color_image_2d_idx = other.radar_color_image_2d_idx; - radar_image_size = other.radar_image_size; - radar_projection_size_mult = other.radar_projection_size_mult; - - ship_iff_info = other.ship_iff_info; - - aiming_flags = other.aiming_flags; - minimum_convergence_distance = other.minimum_convergence_distance; - convergence_distance = other.convergence_distance; - std::swap(convergence_offset, other.convergence_offset); - - emp_resistance_mod = other.emp_resistance_mod; - - piercing_damage_draw_limit = other.piercing_damage_draw_limit; - - damage_lightning_type = other.damage_lightning_type; - - shield_impact_explosion_anim = other.shield_impact_explosion_anim; - std::swap(hud_gauges, other.hud_gauges); - hud_enabled = other.hud_enabled; - hud_retail = other.hud_retail; - - std::swap(displays, other.displays); - - std::swap(pathMetadata, other.pathMetadata); - - std::swap(ship_passive_arcs, other.ship_passive_arcs); - - std::swap(glowpoint_bank_override_map, other.glowpoint_bank_override_map); - - animations = std::move(other.animations); - cockpit_animations = std::move(other.cockpit_animations); - - default_subsys_death_effect = other.default_subsys_death_effect; -} - -ship_info &ship_info::operator= (ship_info&& other) noexcept -{ - if (this != &other) { - move(std::move(other)); - } - return *this; -} - -ship_info::ship_info(ship_info&& other) noexcept -{ - // MageKing17 - Initialize these pointers to NULL because otherwise move() will leave them uninitialized. - subsystems = NULL; - n_subsystems = 0; - - // Then we swap everything (well, everything that matters to the deconstructor). - move(std::move(other)); -} - ship_info::ship_info() { name[0] = '\0'; @@ -1906,7 +1529,6 @@ ship_info::ship_info() generic_debris_spew_num = 20; n_subsystems = 0; - subsystems = NULL; power_output = 0.0f; max_overclocked_speed = 0.0f; @@ -2153,14 +1775,6 @@ ship_info::ship_info() default_subsys_death_effect = particle::ParticleEffectHandle::invalid(); } -ship_info::~ship_info() -{ - if ( subsystems != NULL ) { - delete[] subsystems; - subsystems = nullptr; - } -} - const char* ship_info::get_display_name() const { if (has_display_name()) @@ -5339,8 +4953,9 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool Warning(LOCATION, "Couldn't find preset %s in glowpoints.tbl when parsing ship: %s", name.data(), sip->name); continue; } + int gpo_index = (int)(gpo - glowpoint_bank_overrides.begin()); if(banks == "*") { - sip->glowpoint_bank_override_map[-1] = (void*)(&(*gpo)); + sip->glowpoint_bank_override_map[-1] = gpo_index; continue; } SCP_string banktoken; @@ -5361,11 +4976,11 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool ifrom = atoi(from.data()) - 1; ito = atoi(to.data()) - 1; for(int bank = ifrom; bank <= ito; ++bank) { - sip->glowpoint_bank_override_map[bank] = (void*)(&(*gpo)); + sip->glowpoint_bank_override_map[bank] = gpo_index; } } else { int bank = atoi(banktoken.data()) - 1; - sip->glowpoint_bank_override_map[bank] = (void*)(&(*gpo)); + sip->glowpoint_bank_override_map[bank] = gpo_index; } } while(end !=SCP_string::npos); } @@ -6035,7 +5650,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool // maybe warn if (n_excess_subsystems > 0) { - Warning(LOCATION, "For %s '%s', number of existing subsystems (%d) plus additional subsystems (%d) exceeds max of %d; only the first %d additional subsystems will be used", info_type_name, sip->name, sip->n_subsystems, n_subsystems + n_excess_subsystems, MAX_MODEL_SUBSYSTEMS, n_subsystems); + Warning(LOCATION, "For %s '%s', number of existing subsystems (%d) plus additional subsystems (%d) exceeds max of %d; only the first %d additional subsystems will be used", info_type_name, sip->name, static_cast(sip->n_subsystems), n_subsystems + n_excess_subsystems, MAX_MODEL_SUBSYSTEMS, n_subsystems); } // when done reading subsystems, malloc and copy the subsystem data to the ship info structure @@ -6045,23 +5660,16 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool Assertion(sip->n_subsystems >= 0, "Invalid n_subsystems detected!"); auto new_n = sip->n_subsystems + n_subsystems; - std::unique_ptr subsys_storage(new model_subsystem[MAX(0,new_n)]); - - if(sip->n_subsystems <= 0) { - sip->n_subsystems = n_subsystems; - } else { - // This used realloc originally so we need to copy the existing subsystems to the new storage - std::copy(sip->subsystems, sip->subsystems + sip->n_subsystems, subsys_storage.get()); - - // done with old storage - delete[] sip->subsystems; + std::unique_ptr subsys_storage(new model_subsystem[new_n]); - sip->n_subsystems += n_subsystems; - } - sip->subsystems = subsys_storage.release(); + // This used realloc originally so we need to copy the existing subsystems to the new storage + if (sip->n_subsystems > 0) + std::copy(sip->subsystems.get(), sip->subsystems.get() + sip->n_subsystems, subsys_storage.get()); - Assert(sip->subsystems != NULL); - } + sip->n_subsystems = new_n; + // the old storage (if any) is released by the assignment + sip->subsystems = std::move(subsys_storage); + } for ( int i = 0; i < n_subsystems; i++ ){ sip->subsystems[orig_n_subsystems+i] = subsystems[i]; @@ -11750,9 +11358,9 @@ int ship_create(matrix* orient, vec3d* pos, int ship_type, const char* ship_name for (int bank = 0; bank < pm->n_glow_point_banks; bank++) { glow_point_bank_override* gpo = nullptr; - SCP_unordered_map::iterator gpoi = sip->glowpoint_bank_override_map.find(bank); + auto gpoi = sip->glowpoint_bank_override_map.find(bank); if (gpoi != sip->glowpoint_bank_override_map.end()) { - gpo = (glow_point_bank_override*)sip->glowpoint_bank_override_map[bank]; + gpo = &glowpoint_bank_overrides[gpoi->second]; } if (gpo) { @@ -11902,9 +11510,9 @@ static void ship_model_change(int n, int ship_type) for (int bank = 0; bank < pm->n_glow_point_banks; bank++) { glow_point_bank_override* gpo = nullptr; - SCP_unordered_map::iterator gpoi = sip->glowpoint_bank_override_map.find(bank); + auto gpoi = sip->glowpoint_bank_override_map.find(bank); if (gpoi != sip->glowpoint_bank_override_map.end()) { - gpo = (glow_point_bank_override*)sip->glowpoint_bank_override_map[bank]; + gpo = &glowpoint_bank_overrides[gpoi->second]; } if (gpo) { diff --git a/code/ship/ship.h b/code/ship/ship.h index 636084b9186..d2ee5e47fe6 100644 --- a/code/ship/ship.h +++ b/code/ship/ship.h @@ -27,6 +27,7 @@ #include "weapon/trails.h" #include "ship/anchor_t.h" #include "ship/ship_flags.h" +#include "utils/reset_on_move.h" #include "weapon/weapon_flags.h" #include "weapon/weapon.h" #include "ai/ai.h" @@ -1269,8 +1270,10 @@ class ship_info int generic_debris_spew_num; // subsystem information - int n_subsystems; // this number comes from ships.tbl - model_subsystem *subsystems; // see model.h for structure definition + // (n_subsystems describes the subsystems array; the wrapper keeps it + // consistent with the array by resetting it to 0 in a moved-from ship_info) + util::reset_on_move n_subsystems; // this number comes from ships.tbl + std::unique_ptr subsystems; // see model.h for structure definition particle::ParticleEffectHandle default_subsys_death_effect; // Energy Transfer System fields @@ -1504,7 +1507,7 @@ class ship_info SCP_map pathMetadata; - SCP_unordered_map glowpoint_bank_override_map; + SCP_unordered_map glowpoint_bank_override_map; // key: glowpoint bank (-1 = all banks); value: index into the growable global glowpoint_bank_overrides vector animation::ModelAnimationSet animations; animation::ModelAnimationSet cockpit_animations; @@ -1512,12 +1515,15 @@ class ship_info SCP_vector ship_passive_arcs; ship_info(); - ~ship_info(); + ~ship_info() = default; void clone(const ship_info& other); - ship_info(ship_info&& other) noexcept; + ship_info(ship_info&& other) = default; // NOLINT(performance-noexcept-move-constructor) - not declared noexcept because the implicit exception specification differs by standard library + ship_info &operator=(ship_info&& other) = default; // NOLINT(performance-noexcept-move-constructor) - ditto - ship_info &operator=(ship_info&& other) noexcept; + // Deleted so nobody copies a ship class by accident; use clone() for a deliberate deep copy. + ship_info(const ship_info& other) = delete; + ship_info &operator=(const ship_info& other) = delete; //Helper functions @@ -1534,12 +1540,6 @@ class ship_info const char* get_display_name() const; bool has_display_name() const; -private: - void move(ship_info&& other); - - // Private and unimplemented so nobody tries to use them by accident. - ship_info(const ship_info& other); - const ship_info &operator=(const ship_info& other); }; extern flag_def_list_new Ship_flags[]; diff --git a/code/utils/reset_on_move.h b/code/utils/reset_on_move.h index dd5a1a1b319..98e3492b89e 100644 --- a/code/utils/reset_on_move.h +++ b/code/utils/reset_on_move.h @@ -6,7 +6,7 @@ namespace util { /** - * @brief A trivially-copyable value whose MOVE resets the source to a sentinel. + * @brief A handle-like value whose MOVE resets the source to a sentinel. * * Intended for raw owning handles (heap pointers, bitmap/sound handles) inside * structs that are stored by value in containers. An implicitly-generated move @@ -20,6 +20,15 @@ namespace util * the underlying resource. Types whose copies must deep-copy (or never copy) * should delete or implement their own copy operations. * + * Likewise, move-assignment OVERWRITES the destination's old value WITHOUT + * releasing it, because the wrapper does not know how to release the resource + * either. This is correct when move-assignment only ever targets empty or + * moved-from elements (e.g. vector reallocation and erase shifts); a type + * whose occupied instances can be move-assigned over must release the old + * resource itself, either in hand-written move operations or by using a + * smart pointer member instead. In short: reset_on_move occupies the niche + * between a raw handle and unique_ptr -- move hygiene without RAII. + * * @tparam T the handle type (e.g. some_type*, int) * @tparam NullVal the sentinel a moved-from handle is reset to */