Fix a lifetime issue with hotkey records (fixes #7183)

wmi_manager::set_item would replace a wml_menu_item object with a new one whose state was copied
from the old, but the old one was destroyed *after* the new one was constructed. That means when
the new object (and hence the new record) was created, it would not update the entry in the master
hotkey command info list, since the old still existed. The old object (and its record) would then
be destroyed, performing cleanup in the process, and resulting in the bug.

A new wml_menu_item object constructed from the state of the old one now takes control of its
record as well, so the new object has sole control over its lifetime and the hotkey info can be
appropriately updated.
This commit is contained in:
Charles Dang 2023-03-22 01:04:44 -04:00
parent 9bb3408ab0
commit fa938c9fb1
3 changed files with 7 additions and 2 deletions

View file

@ -115,10 +115,11 @@ wml_menu_item::wml_menu_item(const std::string& id, const vconfig& definition)
}
// Constructor for items modified by an event.
wml_menu_item::wml_menu_item(const std::string& id, const vconfig& definition, const wml_menu_item& original)
wml_menu_item::wml_menu_item(const std::string& id, const vconfig& definition, wml_menu_item& original)
: item_id_(id)
, event_name_(make_item_name(id))
, hotkey_id_(make_item_hotkey(id))
, hotkey_record_(std::move(original.hotkey_record_)) // Make sure we have full lifetime control of the old record
, image_(original.image_)
, description_(original.description_)
, needs_select_(original.needs_select_)

View file

@ -60,7 +60,7 @@ public:
* @param[in] definition The WML defining this menu item.
* @param[in] original The previous version of the menu item with this id.
*/
wml_menu_item(const std::string& id, const vconfig& definition, const wml_menu_item& original);
wml_menu_item(const std::string& id, const vconfig& definition, wml_menu_item& original);
/** The id of this item. */
const std::string& id() const

View file

@ -326,6 +326,10 @@ public:
wml_hotkey_record(const wml_hotkey_record&) = delete;
const wml_hotkey_record& operator=(const wml_hotkey_record&) = delete;
/** But we *do* want move semantics. */
wml_hotkey_record(wml_hotkey_record&&) = default;
wml_hotkey_record& operator=(wml_hotkey_record&&) = default;
/** Registers a hotkey_command for a WML hotkey with the given ID if one does not already exist. */
wml_hotkey_record(const std::string& id, const t_string& description, const config& default_hotkey);