Тяжкая судьба C++программиста довела использования в коде трюка, про который еще несколько лет назад и вовсе не знал. Речь про замену типа объекта через вызов placement new внутри метода самого заменяемого объекта.
В моем случае получился код вроде вот такого:
|
template< typename ValueT > void special_map< ValueT >::fixed_capacity_node::insert_item( ValueT value ) { auto & self = this->self_data(); if( self.size() < self.capacity() ) { ... // use the existing node. } else { ... // prepare internal data for a new node type. // Replace the node by an instance of the new type. new(this) dynamic_capacity_node{ std::move(new_node_internal_data) }; } } |
Т.е. есть объект типа fixed_capacity_node в котором имеется контейнер для небольшого количества элементов. При вставке очередного элемента может оказаться, что этот контейнер исчерпан и нужно перейти к использованию dynamic_capacity_node вместо fixed_capacity_node. Для чего новый объект dynamic_capacity_node и создается. Но не просто так, а в той области памяти, которую только что занимал старый fixed_capacity_node объект.
Еще несколько лет назад мне и в голову не приходило, что такое возможно. Однако, когда изучал тему std::launder, то наткнулся на подобный трюк. И вот теперь сам дошел до его применения.
PS. Никому не советую повторять подобное в домашних условиях. Как говорится, все показанное было выполнено специально подготовленными профессионалами 😎 Были предприняты различные предохранительные меры дабы удостоверится, что fixed_capacty_node и dynamic_capacity_node идентичны и по размеру, и по выравниваю. И что после смены типа объекта никто не обращался к нему по старому указателю без std::launder.