Программирование >>  Арифметические и логические операции 

1 ... 38 39 40 [ 41 ] 42 43 44 ... 53


Другой способ - компилировать с ключом -B. Правда, при этом могут возникнуть другие проблемы: если присутствуют имена read и read (например), то компилятор в них запутается.

Было замечено, что борланд (3.1, например) иногда генерит разный код в зависимости от ключа -B. Как правило, при его наличии он становится осторожнее - начинает понимать, что не он один использует регистры.

Возврат адреса/ссылки локальных переменных - почему возвращает фигню: char* myview() { char s(SIZE); ... return s; }

Нужно поставить static char s[SIZE]; чтобы возвращался адрес всегда существующей (статической) переменной, а автоматические переменные исчезают при выходе из функции - освобождается и может быть замусорено место из-под этих переменных на стеке.

Какие ограничения на имена с подчёркиванием?

При использовании зарезервированных имён (то есть с подчёркиваниями) возможен самый разный undefined behavior. Например, в компиляторе все слова с двойным подчёркиванием могут использоваться для управления файловой системой. Именно поэтому вполне допустимо (по стандарту), если Борланд в своём компиляторе, например, при встрече нестандартной лексемы asm из сорца для VC++ просто потрёт какой-нибудь файл. На практике такого рода вариации undefined behavior встретить сложно, но вполне возможно.

Другие вариации undefined behavior - это всякие глюки при работе программы. То есть, если мы, например, в printf задействуем неизвестный библиотеке (нестандартный) флаг, то по стандарту вполне допустимо не проверять в библиотеке подобную фигню и передать управление куда-нибудь в область данных (ну нет в таблице переходов такого флага!).

Поведение переменных, описанных в заголовке цикла for

Переменная, объявленная в заголовке цикла (и прочих операторов!) действительна только внутри этого цикла.

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

В новых редакциях C++ область видимости определённой в заголовке for переменной ограничивают телом цикла. Следующая подстановка ограничивает область видимости и для старых редакций, в которых она распространяется за пределы цикла:

#define for if(0);else for

а также для BC++ выключим вызываемые if(0) предупреждения:

Condition is always false #pragma warn -ccc

Что есть const после имени метода?

Это означает, что этот метод не будет менять данные класса.

Методы с модификатором const могут изменять данные объекта, помеченные модификатором mutable.

class Bart private:

mutable int m iSomething; public:

void addToSomething( int iValue ) const {

m iSomething += iValue; Bart()

m iSomething = 0; };

const Bart bartObject; bartOb]ect.addToSomething( 8 );

Будет скомпилировано и выполнено.

Как инициализировать статические члены класса?

struct a { static int i; };

int a::i; зачем это нужно?

int main() { a::i = 11; return 0; }

А вот зачем:

struct b { int n; b(int i) :n(i) {} }; struct a { static b i; }; b a::i(0);

int main() { printf( %i\n ,a::i.n); return 0; }

Описание некоего типа и переменная этого типа - не одно и то же. Где вы предлагаете размещать и конструировать статические поля? Может быть, в каждом файле, который включает заголовок с описанием класса? Или где?

Как не ошибиться в размере аллокируемого блока?



Для избежания подобного можно в С сымитировать Сиплюсный

new:

#define tmalloc(type) ((type*)malloc(sizeof(type)))

#define amalloc(type, size) ((type*)malloc(sizeof(type) * (size))) Более того, в последнем define можно поставить (size) + 1, чтобы гарантированно избежать проблем с завершающим нулём в строках.

Можно сделать иначе. Поскольку присвоение от malloc() как правило делают на типизованную переменную, то можно прямо так и написать:

body = malloc(sizeof(*body)); теперь спокойно можно менять типы не заботясь о malloc(). Но это верно для Си, который не ругается на присвоение void* к type* (иначе пришлось бы кастить поинтер, и компилятор изменения типа просто не пережил

бы).

Вообще в C нет смысла ставить преобразования от void* к указательному типу явно. Более того, этот код не переносим на C++ - в проекте стандарта C++ нет malloc() и free(), их нет даже в hosted С++ заголовках. Проще будет:

#ifdef cplusplus

# define tmalloc(type) (new type)

# define amalloc(type, size) (new type[size]) #else

# define tmalloc(type) malloc(sizeof(type))

# define amalloc(type, size) malloc(sizeof(type) * (size)) #endif

Что такое ссылка?

Ссылка - это псевдоним (другое имя) для объекта.

Ссылки часто используются для передачи параметра по ссылке:

void swap(int& i, int& j) {

int tmp = i;

i = j;

j = tmp;

int main()

int x, y;

swap(x,y);

В этом примере i и j - псевдонимы для переменных x и y функции main. Другими словами, i - это x. Не указатель на x и не копия x, а сам x. Все, что вы делаете с i, проделывается с x, и наоборот.

Вот таким образом вы как программист должны воспринимать ссылки. Теперь, рискуя дать вам неверное представление, несколько слов о том, каков механизм работы ссылок. В основе ссылки i на объект x - лежит, как правило, просто машинный адрес объекта x. Но когда вы пишете i++, компилятор генерирует код, который инкрементирует x. В частности, сам адрес, который компилятор использует, чтобы найти x, остается неизменным. Программист на С может думать об этом, как если бы использовалась передача параметра по указателю, в духе языка С, но, во-первых, & (взятие адреса) было бы перемещено из вызывающей функции в вызываемую, и, во-вторых, в вызываемой функции были бы убраны * (разыменование). Другими словами, программист на С может думать об i как о макроопределении для (*p), где p - это указатель на x (т.е., компилятор автоматически разыменовывает подлежащий указатель: i++ заменяется на (*p)++, а i = 7 на *p = 7).

Важное замечание: несмотря на то что в качестве ссылки в окончательном машинном коде часто используется адрес, не думайте о ссылке просто как о забавно выглядящем указателе на объект. Ссылка - это объект. Это не указатель на объект и не копия объекта. Это сам объект.

Что происходит в результате присваивания ссылке?

Вы меняете состояние ссыльного объекта (того, на который ссылается ссылка).

Помните: ссылка - это сам объект, поэтому, изменяя ссылку, вы меняете состояние объекта, на который она ссылается. На языке производителей компиляторов ссылка - это lvalue (left value - значение, которое может появиться слева от оператора присваивания).

Что происходит, когда я возвращаю из функции ссылку?

В этом случае вызов функции может оказаться с левой стороны оператора (операции) присваивания.

На первый взгляд, такая запись может показаться странной. Например, запись f() = 7 выглядит бессмысленной. Однако, если a - это объект класса Array, для большинства людей запись a[i] = 7 является осмысленной, хотя a[i] - это всего лишь замаскированный вызов функции Array::operator[](int), которая является оператором обращения по индексу для класса Array:



class Array { public: int size() const; floats operator[] (int index);

int main()

Array a;

for (int i = 0; i < a.size(); ++i) a[i] = 7; В этой строке вызывается Array::operator[](int)

Как можно переустановить ссылку, чтобы она ссылалась на другой объект?

Невозможно в принципе.

Невозможно отделить ссылку от ее объекта.

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

С этой точки зрения, ссылка похожа на const указатель, такой как int* const p (в отличие от указателя на const, такого как const int* p). Несмотря на большую схожесть, не путайте ссылки с указателями - это не одно и то же.

В каких случаях мне стоит использовать ссылки, и в каких - указатели?

Используйте ссылки, когда можете, а указатели - когда это необходимо.

Ссылки обычно предпочтительней указателей, когда вам не нужно их перенаправлять . Это обычно означает, что ссылки особенно полезны в открытой (public) части класса. Ссылки обычно появляются на поверхности объекта, а указатели спрятаны внутри.

Исключением является тот случай, когда параметр или возвращаемый из функции объект требует выделения охранного значения для особых случаев. Это обычно реализуется путем взятия/возвращения указателя, и обозначением особого случая при помощи передачи нулевого указателя (NULL).

Ссылка же не может ссылаться на разыменованный нулевой указатель.

Примечание: программисты с опытом работы на С часто недолюбливают ссылки, из-за того что передача параметра по ссылке явно никак не обозначается в вызывающем коде. Однако с обретением некоторого опыта работы на С++, они осознают, что это одна из форм сокрытия информации, которая является скорее преимуществом, чем недостатком. Т.е., программисту следует писать код в терминах задачи, а не компьютера (programmers should write code in the language of the problem rather than the language of the machine).

Что такое встроенная функция?

Встроенная функция - это функция, код которой прямо вставляется в том месте, где она вызвана. Как и макросы, определенные через #define, встроенные функции улучшают производительность за счет стоимости вызова и (особенно!) за счет возможности дополнительной оптимизации ( процедурная интеграция ).

Как встроенные функции могут влиять на соотношение безопасности и скорости?

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

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

Стоимость вызова функции невелика, но дает некоторую прибавку. Классы С+ + позволяют встраивание функций, что дает вам безопасность инкапсуляции вместе со скоростью прямого доступа. Более того, типы параметры встраиваемых функций проверяются компилятором, что является преимуществом по сравнению с сишными #define макросами.



1 ... 38 39 40 [ 41 ] 42 43 44 ... 53

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