Урок №127. Анонимные объекты

  Юрий  | 

  |

  Обновл. 13 Сен 2021  | 

 46332

 ǀ   8 

В некоторых случаях в языке C++ переменная может быть нам нужна только временно. Например:

В функции add() переменная result используется как временная переменная. Она не выполняет особой роли, функция использует её только для возврата значения.

Есть более простой способ написать функцию add() — через анонимный объект. Анонимный объект — это значение без имени. Поскольку имени нет, то и способа ссылаться на этот объект за пределами места, где он создан — тоже нет. Следовательно, анонимные объекты имеют область видимости выражения и они создаются, обрабатываются и уничтожаются в пределах одного выражения.

Вот функция add(), приведенная выше, но уже с использованием анонимного объекта:

При вычислении выражения a + b, результат помещается в анонимный объект. Затем копия анонимного объекта возвращается по значению обратно в caller, и анонимный объект уничтожается.

Это работает не только с возвращаемыми значениями, но и с параметрами функции. Например, вместо этого:

Мы можем написать это:

В этом случае выражение 4 + 2 генерирует результат 6, который помещается в анонимный объект. Затем копия этого анонимного объекта передается в функцию printResult() (которая выводит значение 6) и уничтожается.

Обратите внимание, насколько чище стал наш код — нам не нужно засорять его временными переменными, которые используются только один раз.

Анонимные объекты класса

Хотя в вышеприведенных примерах мы использовали только фундаментальные типы данных, анонимные объекты также могут использоваться и с классами. Достаточно просто не указывать имя объекта:

В примере, приведенном выше, строка Dollars(8); создаст анонимный объект класса Dollars, инициализирует его значением 8, а затем уничтожит. В этом контексте пользы мы много не получим. Рассмотрим пример, где это может принести пользу:

Здесь функция main() передает объект dollars в функцию print(). Мы можем упростить эту программу, используя анонимные объекты:

Результат выполнения программы:

7 dollars.

Теперь рассмотрим пример сложнее:

В функции add() у нас есть значение переменной sum класса Dollars, которое используется в качестве промежуточного значения для хранения результата и его возврата. И в функции main() у нас есть значение переменной sum класса Dollars, которое также используется, как промежуточное.

Можно сделать проще, используя анонимные объекты:

Эта версия функции add() идентична вышеприведенной функции add(), за исключением того, что вместо отдельного объекта используется анонимный объект класса Dollars. Также обратите внимание, в функции main() мы больше не используем переменную с именем sum. Вместо нее мы используем возвращаемое анонимное значение из функции add()!

В результате, наша программа стала короче, чище и проще. Фактически, поскольку dollars1 и dollars2 используются только в одном месте, мы можем еще упростить этот код с помощью анонимных объектов:

Заключение


Анонимные объекты в языке C++ используются для передачи или возврата значений без необходимости создавать большое количество временных переменных. Динамическое выделение памяти также выполняется через анонимные объекты (поэтому адрес выделенной памяти должен быть присвоен указателю, иначе мы не имели бы способа ссылаться/использовать её).

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

Помните, что анонимные объекты можно использовать только один раз, так как они имеют область видимости выражения. Если вам нужно ссылаться на значение в нескольких выражениях, то для этого следует использовать отдельную переменную.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (264 оценок, среднее: 4,96 из 5)
Загрузка...

Комментариев: 8

  1. Павел:

    Хех, так мы же их уже давно используем, может даже и с первых уроков.

    Но у меня вопрос:

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

    Стоит еще отметить, что анонимные объекты рассматриваются как r-values (а не как l-values, у которых есть адрес).

    Я не понял как через анонимные объекты выделяется динамическая память, если они r-values ?

    int a — объявление переменной с размером выделенной памяти int,

    new int — запрос указателя на адрес памяти из кучи для типа int,

    int *ptr = new int — присваивание адреса памяти указателю ptr,

    указатель — это переменная, значением которой является адрес ячейки памяти,

    переменная — это объект с именем.

    У объекта с именем есть адрес, а значит переменная, или же указатель не являются r-values.

    Значит в выражении int *ptr = new int нет r-values ?

    1. Павел:

      У r-values нет постоянного адреса в памяти.

      В new int возвращается указатель с временным адресом памяти, и, если его некуда присвоить — тут же исчезает. Временный указатель и является значением без имени, т.е анонимным объектом, т.е r-value.

      Так?

  2. Константин:

    Как компилятор узнает, что add — это метод именно анонимного объекта Dollars, а не какого-нибудь другого класса с таким же методом. И вроде получается, что анонимный объект не инициализирован.

    1. otecart:

      Это не метод класса Dollars. Это просто функция. Среди других функций для компилятора её выделит название и принимаемые аргументы.
      А поскольку она возвращает тип Dollars, можно строить конструкции типа add(Dollars(x), Dollars(y)).getDollars(), как и для любого объекта класса Dollars.

  3. kmish:

    "В результате наша программа стала короче, чище и проще. "
    1. Короче — да.
    2. Чище — спорно:
    Не уверен, что

    чище чем

    3. Проще — уж точно не проще это читать.

    1. Александр:

      В всем должен быть баланс.

      можно предложить подход в выборе "выражение или переменная ?" с опором на вложение конструкций (скобки). Если "скобок" становится слишком много (три или более в одном выражении), то лучше разбить на несколько.

  4. Ануар:

    Честно, не самая трудная тема. Особенно для кого-нибудь, кто дошел до 127-ой статьи(я начал с введения в ООП).
    Я бы даже сказал интуитивно понятная тема. Если бы ты использовал это где нибудь в коде в другой теме и даже не закомментил, я бы понял. Но все равно класс.

    1. SuRprizZe:

      хахахах, "класс" в тему)))

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *