|
Программирование >> Обобщенные обратные вызовы
Задача 36. Объединения Сложность: 4 Речь в данной задаче пойдет не о профсоюзах или партиях, а об объединениях в С++, их сильных и слабых сторонах и о правилах использования конструируемых объектов в качестве членов объединений. Вопрос для новичка 1. Что такое объединения и для чего они предназначены? 2. Какие типы не могут использоваться в качестве членов объединений? Почему существуют такие ограничения? Поясните свой ответ. Вопрос для профессионала 3. в статье [Мап1еу02] рассматривается написание языка сценариев, в котором используются объединения. Допустим, что вы хотите, чтобы ваш язык поддерживал единый тип для переменных, которые в разные моменты времени могут хранить целые числа, строки или списки. Создание union {int i; list<int> 1; string s;}; не работает по причинам, которые разбираются в вопросах 1 и 2. Приведенный далее код представляет собой обходной путь, который пытается обеспечить поддержку произвольного типа в качестве участника объединения (более подробную информацию по этому вопросу вы сможете найти в указанной статье.) Отрецензируйте предложенный код и найдите: а) механические ошибки, такие как неверный синтаксис или непереносимые соглашения; б) стилистические улучшения, которые могут повысить ясность исходного текста, его повторное использование и сопровождение. #include <list> #include <string> #include <iostream> usi ng namespace std; #define max(a,b) (a)>(b)?Ca):(b) typedef list<int> list; typedef string string; struct myunion { myuniono : currtypeC none ) {} -myunion0 {cleanupO;} enum uniontype {N0NE, int, list, string}; uniontype currtype; inline int& getintC); inline list& qetlistO; inline string& getstringO ; protected: union { i nt i ; unsigned char buff[max(sizeof(list),sizeof(string))]; } u; void cleanupO ; inline int& myunion::getint() if( currtype== lNT ) { return u.i; } else { cleanupC); currtype= int; return u.i; } else inline list& myunion::getlist() ifС currtype== LiST ) { return *(reinterpret cast<LlST*>(U.buff)); } else { cleanupC); list* ptype = new(u.buff) LiST(); currtype= LiST; return *ptype; } else inline STRING& myunion::getst ri ng() if( currtype== STRlNG) { return *(reinterpret cast<STRlNG*>(u.buff)); } else { cleanupO; string* ptype = new(U.buff) string(); currtype= STRiNG; return *ptype; } else void myunion::cleanupO switch( currtype ) { case list: { list& ptype = getlistO; )type.~LiST(); згеак; } case case STRING: { STRINGS ptype = getstringO; )type.~STRiNG0; згеак; } case default: break; } switch currtype=NONE; 4. Покажите лучший способ получения обобшенного вариантного типа, и расскажите, с какими сложностями вам пришлось столкнуться. Решение Основные сведения 1. Что такое объединения и для чего они предназначены? Объединения позволяют нескольким объектам, как классам, так и встроенным типам, занимать одно и то же место в памяти. Например: Пример 36-1 union и { i nt i ; float f; и u; u.i = 42; АКТИВНО поле i std::cout u.i std::endl; u.f = 3.14f; Активно поле f std::cout 2 * u.f std::endl; Однако в каждый момент времени может быть активен только один тип - в конце концов, память может хранить одновременно только одно значение. Кроме того, объединения поддерживают только некоторые виды типов, что приводит нас к следующему вопросу. 2. Какие типы не могут использоваться в качестве членов объединений? Почему существуют такие ограничения? Поясните свой ответ. Из стандарта С++: Объект класса с нетривиальным конструктором, нетривиальным копирующим конструктором, нетривиальным деструктором или нетривиальным оператором копирующего присваивания, или массив объектов такого класса, не может быть членом объединения. Коротко говоря, чтобы класс мог использоваться в объединении, он должен удовлетворять следующим критериям. Конструкторы, деструкторы и операторы копирующего присваивания должны генерироваться компилятором. Класс не имеет виртуальных функций или виртуальных базовых классов. То же должно быть справедливо для всех его базовых классов и нестатических членов. Вот и все, но это ограничивает применение огро.много количества типов. Объединения унаследованы от С. Традиции языка С включают эффективность и поддержку низкоуровневого, приближенного к аппаратному обеспечению программирования, и эти традиции сохранены и в С++ - вот почему в С++ имеются объединения. С другой стороны, у С нет никаких традиций объектной модели с поддержкой классов с конструкторами и деструкторами и пользовательским копированием, что определенно имеется в С++. Вот почему в С++ использование таких новых типов со старыми объединениями, если таковое имеет место, не должно нарушать объектную модель С++, включая гарантии времени жизни объектов. Если бы в С++ не было указанных ограничений, могли бы происходить Ужасные Вещи. Рассмотрим, например, что могло бы произойти, если бы был разрешен следующий код. пример 36-2: Этот код не соответствует стандарту С++, но что произошло бы, если бы он был разрешен? void f() { union lllegal Immoral AndFattening { std::string s; std::auto ptr<int> p; ll1egalimmoralAndFattening iiaf; iiaf.s = Hello, world ; Вызывать ли конструктор s? iiaf.p = new i nt(4); вызывать ли конструктор p?
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |