- •Формальные свойства алгоритмов
- •Основные определения языка, структура программы на языке Си.
- •1. Алфавит
- •2. Литералы
- •3. Комментарии
- •Основные математические операции
- •Увеличение значения переменной на 1
- •Представление о префиксной (до) и постфиксной (после) операциях увеличения
- •Перегрузка операции присваивания копированием
- •Притянутые за уши примеры использования
- •Перегрузка операции запятая
- •1.4. Операторы
- •1.4.1. Оператор выражение
- •1.4.2. Пустой оператор
- •1.4.3. Составной оператор
- •1.4.4. Оператор if
- •1.4.5. Оператор switch
- •1.4.6. Оператор break
- •1.4.7. Оператор for
- •1.4.8. Оператор while
- •1.4.9. Оператор do while
- •1.4.10. Оператор continue
- •1.4.11. Оператор return
- •1.4.12. Оператор goto
- •Условный оператор
- •13. Массивы
- •14. Указатели
- •16. Операторы ввода-вывода в языке си (c)
- •Препроцессор Си
- •Директивы
- •Функции Включение
- •Условная компиляция
- •Функции возвращающие значение.
- •Функции с параметрами.
- •Статические переменные
- •Передача аргументов по ссылке
- •23. Урок 12. Локальные переменные и область видимости
- •Объявление локальных переменных
- •Глобальные переменные
- •24. Пространство имен
- •25. Стандартная библиотека языка Си
- •Структура
- •[Править]Библиотечные заголовочные файлы ansi Си
- •[Править]Стандартная библиотека Си в других языках
- •[Править]Общая поддержка библиотек
- •[Править]Встроенные функции компилятора
Перегрузка операции присваивания копированием
Когда нужно сделать глубокие копии объектов необходимо также принять во внимание и обработку исключений. Одним из способов избежать ошибки перемещения ресурсов является следующий:
Получаем новые ресурсы
Освобождаем старые ресурсы
Присваиваем объекту значения нового ресурса
class My_Array
{
int * array;
int count;
public:
My_Array & operator = (const My_Array & other)
{
if (this != &other) // защита от неправильного самоприсваивания
{
// 1: выделяем "новую" память и копируем элементы
int * new_array = new int[other.count];
std::copy(other.array, other.array + other.count, new_array);
// 2: освобождаем "старую" память
delete [] array;
// 3: присваиваем значения в "новой" памяти объекту
array = new_array;
count = other.count;
}
// по соглашению всегда возвращаем *this
return *this;
}
...
};
Тем не менее, если успешный метод обмена доступен для всех членов и класс реализует конструктор копирования и деструктор (согласноПравилу трех), самым коротким путем реализации присваивание копированием будет следующий способ[2]:
public:
void swap(My_Array & other) // обмен члена-функции (неудачи быть не должно!)
{
// обмен всех членов (и базовых субобъектов, если возможно) с other
std::swap(array, other.array);
std::swap(count, other.count);
}
My_Array & operator = (My_Array other) // Примечание: аргумент передается по значению!
{
// обмен this с other
swap(other);
// по соглашению всегда возвращаем *this
return *this;
// other уничтожается, освобождая память
}
Причина, по которой операция = возвращает My_Array& вместо void, проста. Он разрешен для объединения назначений, как например:
array_1 = array_2 = array_3; // значение array_3 присваивается array_2
// затем значение array_2 присваивается array_1
Операция запятая в C++
Прежде всего, следует знать, что не всякая запятая в тексте вашей программы являетcя операцией. Перечислим запятые, которые являются не операциями, а разделителями:
Запятые, разделяющие аргументы макроподстановок. Пример:#define MIN(a, b) (((a) < (b)) ? (a) : (b))
Запятые, разделяющие аргументы шаблонов. Пример:template<class A, class B> class C;
Запятые, разделяющие аргументы функции (при её определении, описании, и вызове);
Запятые, разделяющие переменные при описании нескольких переменных:int a, *b, c;
Запятые, разделяющие вызовы конструкторов внутренних объектов. Пример:class C{int x; float y; public: C(void): x(9), y(2.5) { ; } };
Запятые, разделяющие элементы инициализаторов массивов и структур:int a[] = {1, 2, 3};
Остальные запятые являются операциями. Операция запятая имеет самый низкий приоритет среди всех операций языка C++. У этой операции есть 2 операнда (левый и правый). Вначале вычисляется левый операнд, затем правый, а в качестве результата возвращается правый операнд. Тривиальный пример:
int a = (1 + 2, 3 + 4); //В результате a == 3+4 == 7. Заключёно в // скобки, так как иначе запятая была бы // воспринята, как разделитель переменных
Если правый операнд операции запятая является левосторонним выражением (имеет адрес и не является константой), то результатом тоже является левостороннее выражение. В этом случае результату можно присваивать значение или вычислять адрес:
int a = 1, b = 2;(a, b) = 3; //В результате a==1, b==3
Побочные эффекты
Пусть выражение «побочный эффект» вас не пугает, — это действие, совершенно осознанно запрограммированное разработчиком программы. «Побочный» — не обязательно «плохой»; слово приобрело отрицательный оттенок из-за лекарств, которые обычно имеют один терапевтический эффект и много побочных.
Зачем же вычислять значения обоих операндов, если значение левого всё равно не используется? Дело в том, что в процессе вычисления операнда могут быть произведены дополнительные действия, называемые побочными эффектами. Например, могут быть модифицированы какие-либо переменные в программе, или выполнены некоторые внешние действия (вывод на экран, запись на диск).
Операция запятая предназначена для того, чтобы впихивать действия с побочными эффектами в те места программы, где компилятор ожидает один оператор. Как вы увидите далее, от этой возможности языка программирования нет никакой пользы — понятность программы снижается, а дополнительные действия можно выполнить и без запятых.