Программирование >>  Перегруженные имена функций и идентификаторы 

1 ... 158 159 160 [ 161 ] 162 163 164 ... 210


использовать переменную в параллельных процедурах (например, обработчиках прерываний). Чтобы компилятор не изничтожал такую переменную и не делал её регистровой придумали ключевое слово volatile.

longjmp получает переменная типа jmp buf, в которой setjmp сохраняет текущий контекст (все регистры), кроме значения переменных. То есть если между setjmp и longjmp переменная изменится, её значение восстановлено не будет.

Содержимое переменной типа jmp buf никто никогда (кроме setjmp) не модифицирует - компилятор просто не знает про это, потому что все это не языковое средство.

Поэтому при longjmp в отличие от прочих регистровые переменные вернутся в исходное состояние (и избежать этого нельзя). Также компилятор обычно не знает, что вызов функции может привести к передаче управления в пределах данной функции. Поэтому в некоторых случаях он может не изменить значение переменной (например, полагая ее выходящей из области использования).

Модификатор volatile в данном случае поможет только тем переменным, к к которым он применён, поскольку он никак не влияет на оптимизацию работы с другими переменными...

Как получить адрес члена класса?

Поскольку указатель на член, в отличие от простого указателя, должен хранить также и контекстную информацию, поэтому его тип отличается от прочих указателей и не может быть приведён к void*. Выглядит же он так:

int i; int f();

struct X int i; int f(); x,

*px = &x;

int *pi = &i; i = *pi;

int (*pf)() = &f; i = (*pf)();

int X::*pxi = &X::i; i = x.*pxi;

int (X::*pxf)() = &X::f;

i = (px->*pxf)();

Зачем нужен for, если он практически идентичен while?

Уточним различие циклов for и while:

for позволяет иметь локальные переменные с инициализацией;



continue не обходит стороной выражение шага, поэтому

for(int i = 0; i < 10; ... continue; ...

не идентично

int i = 0; while(i < 10) ... continue; ... i++

Зачем нужен NULL?

Формально стандарты утверждают, что NULL идентичен 0 и для обоих гарантируется корректное преобразование к типу указателя.

Ho разница есть для случая функций с переменным числом аргументов (например, print!) - не зная типа параметров компилятор не может преобразовать 0 к типу указателя (а на писюках NULL может быть равным 0L).

С другой стороны, в нынешней редакции стандарта NULL не спасёт в случае полиморфности: когда параметр в одной функции int, а в другой указатель, при вызове и с 0, и с NULL будет вызвана первая.

Безопасно ли delete NULL? Можно ли применять delete[]var после new var[]? А что будет при delete data; delete data?

delete NULL (как и free(NULL)) по стандарту безопасны;

delete[] после new, как и delete после new[] по стандарту применять нельзя.

Если какие-то реализации допускают это - это их проблемы;

повторное применение delete к освобождённому (или просто не выделенному участку) обладает неопределённым поведением и может вызвать всё, что угодно - core dump, сообщение об ошибке, форматирование диска и прочее;

последняя проблема может проявиться следующим образом:

new data1; delete data1; new data2;

delete data1; delete data2; Что за чехарда с конструкторами? Деструкторы явно вызываются чаще...

На это существует неписанное Правило Большой четвёрки : если вы сами не озаботитесь о дефолтном конструкторе, конструкторе копирования, операторе



присваивания и виртуальном деструкторе, то либо Старший Брат озаботит вас этим по умолчанию (первые три), либо через указатель будет дестроиться некорректно (четвёртый).

Например:

struct String1 ... char *ptr; ... String1 &operator = (String1&); ... ;

struct String2 ... char array[lala]; ... ;

В результате отсутствия оператора присваивания в String2 происходило лишнее копирование String2::array в дефолтном операторе присваивания, поскольку String1::operator = и так уже дублировал строку ptr. Пришлось вставить.

Так же часто забывают про конструктор копирования, который вызывается для передачи по значению и для временных объектов. А ещё есть чехарда с тем, что считать конструктором копирования или операторами присваивания:

struct C0 C0 &operator = (C0 &src) puts( C0= ); return *this; ; struct C1 :C0 C0 &

operator = (C0 &src) puts( C1= ); return *this;

int main()

C1 c1, c2; c1 = c2;

Некоторые считают, что здесь должен быть вызван дефолтный оператор присваивания C1::operator=(C1&) (а не C1::operator=(C0&)), который, собственно, уже вызовет C0::operator=(C0&).

Понадобилось написать метод объекта на ассемблере, а Ватком строит имена так, что это невозможно - стоит знак : в середине метки, типа xcvvxxiswsw. Какие ключи нужны чтобы он такого не делал?

class A;

extern C int ClassMetod Call2Asm (A*, ...); class A

int Call2Asm(...) return ClassMetod Call2Asm(this, ...);

Сожрет любой Cpp компилятор. Для методов, которые вы хотите вызывать из asm - аналогично...

Так можно произвольно менять генерацию имён в Watcom:

#pragma aux var



1 ... 158 159 160 [ 161 ] 162 163 164 ... 210

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