Программирование >>  Обобщенные обратные вызовы 

1 ... 67 68 69 [ 70 ] 71 72 73 ... 84


Задача 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?



1 ... 67 68 69 [ 70 ] 71 72 73 ... 84

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика