Чем заменить return в c

Использование throw для замены return в C ++ не пустых функциях

Код выше компилируется с моим GCC 7.2.

7 ответов

То, что функция вызывает последний вызов, не означает, что она заменяет return. Это просто поток логики.

Вопрос не должен быть:

это хорошая практика, чтобы заменить возврат броска?

В обоих случаях пользователь должен знать, какие действия он должен предпринять, чтобы правильно использовать вашу функцию.

Как правило, исключения означают, что во время выполнения вашего кода произошло что-то ненормальное или неожиданное. Глядя на назначение вашей функции, появление двух целых чисел в переданном векторном суммировании в target является очень возможным результатом функции, поэтому результат не является ненормальным и, следовательно, не должен рассматриваться как исключительный.

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

Как правило, программисты на C ++ предпочитают писать функции, которым не нужно генерировать исключения, чтобы сообщать о простых «разочарованиях», таких как сбои поиска, которые легко предвидеть и обрабатывать локально. Преимущества возврата значений вместо выдачи исключений широко обсуждаются в других местах, поэтому я не буду перефразировать это обсуждение здесь.

Таким образом, объявление «сбой» путем выдачи исключения обычно ограничивается следующими случаями:

В функциях C ++, является ли хорошей практикой замена return на throw?

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

Постскриптум Вектор, вероятно, не является хорошим выбором для возврата пары чисел. std::pair может быть лучше, или пользовательский класс, если у вас есть хорошие имена для чисел.

Источник

ref locals и ref returns в C#: подводные камни производительности

В языке C# с самого начала поддерживалась передача аргументов по значению или по ссылке. Но до версии 7 компилятор C# поддерживал только один способ возврата значения из метода (или свойства) — возврат по значению. В C# 7 ситуация изменилась с введением двух новых возможностей: ref returns и ref locals. Подробнее о них и об их производительности — под катом.

Чем заменить return в c. Смотреть фото Чем заменить return в c. Смотреть картинку Чем заменить return в c. Картинка про Чем заменить return в c. Фото Чем заменить return в c

Причины

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

Чтобы продемонстрировать это, нам придется обратиться к запретному методу — воспользоваться изменяемым (mutable) типом значения:

Тестирование пройдет успешно, потому что индексатор массива значительно отличается от индексатора List.

Компилятор C# дает специальную инструкцию индексатору массивов — ldelema, которая возвращает управляемую ссылку на элемент данного массива. По сути, индексатор массива возвращает элемент по ссылке. Однако List не может вести себя таким же образом, потому что в C# было невозможно* вернуть псевдоним внутреннего состояния. Поэтому индексатор List возвращает элемент по значению, то есть возвращает копию данного элемента.

*Как мы скоро увидим, индексатор List по-прежнему не может возвращать элемент по ссылке.

Это значит, что ma[0].IncrementX() вызывает метод, изменяющий первый элемент массива, в то время как ml[0].IncrementX() вызывает метод, изменяющий копию элемента, не затрагивая исходный список.

Возвращаемые ссылочные значения и ссылочные локальные переменные: основы

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

2. Возвращаемые ссылочные значения и модификатор readonly

Возвращаемое ссылочное значение может вернуть псевдоним поля экземпляра, а начиная с C# версии 7.2, можно возвращать псевдоним без возможности записи в соответствующий объект, используя модификатор ref readonly:

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

Использование возвращаемых ссылочных значений в индексаторах

Чтобы проверить влияние этих функций на производительность, мы создадим уникальную неизменяемую коллекцию по названием NaiveImmutableList и сравним ее с T[] и List для структур разного размера (4, 16, 32 и 48).

Тест производительности выполняется для всех коллекций и складывает все значения свойств N для каждого элемента:

Чем заменить return в c. Смотреть фото Чем заменить return в c. Смотреть картинку Чем заменить return в c. Картинка про Чем заменить return в c. Фото Чем заменить return в c

Видимо, что-то не так! Производительность нашей коллекции NaiveImmutableList такая же, как и у List. Что же произошло?

Возвращаемые ссылочные значения с модификатором readonly: как это работает

Как можно заметить, индексатор NaiveImmutableList возвращает ссылку, доступную только для чтения, с помощью модификатора ref readonly. Это полностью оправданно, так как мы хотим ограничить возможности клиентов в плане изменения основного состояния неизменяемой коллекции. Однако используемые нами в тесте производительности структуры доступны не только для чтения.

Данный тест поможет нам понять базовое поведение:

Тест прошел неудачно! Но почему? Потому что структура «ссылок, доступных только для чтения» похожа на структуру модификаторов in и полей readonly в отношении структур: компилятор генерирует защитную копию каждый раз, когда используется элемент структуры. Это значит, что ml[0]. по-прежнему создает копию первого элемента, но это делает не индексатор: копия создается в точке вызова.

Такое поведение на самом деле имеет смысл. Компилятор C# поддерживает передачу аргументов по значению, по ссылке и по «ссылке только для чтения», используя модификатор in (подробную информацию см. в публикации The in-modifier and the readonly structs in C# («Модификатор in и структуры только для чтения в C#»)). Теперь компилятор поддерживает три разных способа возврата значения из метода: по значению, по ссылке и по ссылке только для чтения.

«Ссылки только для чтения» настолько похожи на обычные, что компилятор использует один и тот же InAttribute для различения их возвращаемых значений:

В этом случае метод ByReadonlyRef эффективно компилируется в:

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

Помимо необычного синтаксиса при объявлении переменной для bigStruct, код выглядит нормально. Цель ясна: BigStruct возвращается по ссылке из соображений производительности. К сожалению, поскольку структура BigStruct доступна для записи, каждый раз при доступе к элементу создается защитная копия.

Использование возвращаемых ссылочных значений в индексаторах. Попытка № 2

Давайте опробуем тот же набор тестов в отношении структур только для чтения разных размеров:

Чем заменить return в c. Смотреть фото Чем заменить return в c. Смотреть картинку Чем заменить return в c. Картинка про Чем заменить return в c. Фото Чем заменить return в c

Теперь в результатах гораздо больше смысла. Время обработки по-прежнему увеличивается для больших структур, но это ожидаемо, потому что обработка более 100 тысяч структур большего размера занимает больше времени. Но теперь время работы для NaiveimmutableList очень близко ко времени T[] и значительно лучше, чем в случае с List.

Заключение

P. S. Ссылки только для чтения появятся в BCL. Методы readonly ref для доступа к элементам неизменных коллекций были представлены в следующем запросе на включение внесенных изменений в corefx repo (Implementing ItemRef API Proposal («Предложение на включение ItemRef API»)). Поэтому очень важно, чтобы все понимали особенности использования этих функций и то, как и когда их следует применять.

Источник

ref (Справочник по C#)

Ключевое слово ref указывает, что значение передается по ссылке. Оно используется в четырех разных контекстах:

Передача аргументов по ссылке

При использовании в списке параметров метода ключевое слово ref указывает на то, что аргумент передается по ссылке, а не по значению. Ключевое слово ref позволяет превратить этот формальный параметр в псевдоним для аргумента, который должен представлять собой переменную. Другими словами, любая операция в параметре осуществляется с аргументом.

Для примера предположим, что вызывающая сторона передает выражение локальной переменной или выражение доступа к элементу массива. Тогда вызываемый метод может заменить объект, на который ссылается параметр ref. В этом случае или элемент массива или локальная переменная вызывающей стороны будет ссылаться на новый объект, когда метод возвращает значение.

Не путайте понятие передачи по ссылке с понятием ссылочных типов. Эти два понятия не совпадают. Параметр метода может быть изменен с помощью ref независимо от того, принадлежит ли он к типу значения или ссылочному типу. При передаче по ссылке упаковка-преобразование типа значения не производится.

Методы расширения также имеют ряд ограничений при использовании этих ключевых слов:

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

Дополнительные сведения о передаче ссылочных типов по значению и по ссылке см. в разделе Передача параметров ссылочного типа.

Возвращаемые ссылочные значения

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

Возвращаемое ссылочное значение определяется с помощью ключевого слова ref :

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

Ниже приведен более полный пример возвращаемого ссылочного значения, в котором показаны сигнатура и тело метода.

Ссылочные локальные переменные

Чтобы определить локальное ссылочное значение, ключевое слово ref следует указать в двух местах:

Например, следующая инструкция определяет значение ссылочной локальной переменной, которое возвращается методом GetEstimatedValue :

Вы можете таким же образом обратиться к значению по ссылке. В некоторых случаях обращение к значению по ссылке повышает производительность, поскольку позволяет избежать потенциально затратной операции копирования. Например, следующая инструкция позволяет определить локальную ссылочную переменную, которая используется для создания ссылки на значение.

В обоих примерах ключевое слово ref необходимо использовать в обоих местах. В противном случае возникает ошибка компилятора CS8172, «Невозможно инициализировать значением переменную по ссылке».

Начиная с версии C# 7.3, переменная итерации в операторе foreach может являться локальной ссылочной переменной или локальной ссылочной переменной только для чтения. Дополнительные сведения см. в статье, посвященной инструкции foreach.

Также, начиная с версии C# 7.3, вы можете переназначать ссылочную локальную переменную или ссылочную локальную переменную только для чтения с помощью ссылочного оператора присваивания.

Ссылочные локальные переменные только для чтения

Пример использования возвращаемых ссылочных значений и ссылочных локальных переменных

Спецификация языка C#

Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

Источник

Урок №12. Функции

Обновл. 26 Ноя 2021 |

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

Функции

Функция — это последовательность стейтментов для выполнения определенного задания. Часто ваши программы будут прерывать выполнение одних функций ради выполнения других. Вы делаете аналогичные вещи в реальной жизни постоянно. Например, вы читаете книгу и вспомнили, что должны были сделать телефонный звонок. Вы оставляете закладку в своей книге, берете телефон и набираете номер. После того, как вы уже поговорили, вы возвращаетесь к чтению: к той странице, на которой остановились.

Программы на языке C++ работают похожим образом. Иногда, когда программа выполняет код, она может столкнуться с вызовом функции. Вызов функции — это выражение, которое указывает процессору прервать выполнение текущей функции и приступить к выполнению другой функции. Процессор «оставляет закладку» в текущей точке выполнения, а затем выполняет вызываемую функцию. Когда выполнение вызываемой функции завершено, процессор возвращается к закладке и возобновляет выполнение прерванной функции.

Функция, в которой находится вызов, называется caller, а функция, которую вызывают — вызываемая функция, например:

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

Starting main()
In doPrint()
Ending main()

Правило: Не забывайте указывать круглые скобки () при вызове функций.

Возвращаемые значения

Когда функция main() завершает свое выполнение, она возвращает целочисленное значение обратно в операционную систему, используя оператор return.

Функции, которые мы пишем, также могут возвращать значения. Для этого нужно указать тип возвращаемого значения (или «тип возврата»). Он указывается при объявлении функции, перед её именем. Обратите внимание, тип возврата не указывает, какое именно значение будет возвращаться. Он указывает только тип этого значения.

Затем, внутри вызываемой функции, мы используем оператор return, чтобы указать возвращаемое значение — какое именно значение будет возвращаться обратно в caller.

Рассмотрим простую функцию, которая возвращает целочисленное значение:

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

Первый вызов функции return7() возвращает 7 обратно в caller, которое затем передается в std::cout для вывода.

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

Примечание: Возвращаемые значения не выводятся на экран, если их не передать объекту std::cout. В последнем вызове функции return7() значение не отправляется в std::cout, поэтому ничего и не происходит.

Тип возврата void

Функции могут и не возвращать значения. Чтобы сообщить компилятору, что функция не возвращает значение, нужно использовать тип возврата void. Взглянем еще раз на функцию doPrint() из вышеприведенного примера:

Эта функция имеет тип возврата void, который означает, что функция не возвращает значения. Поскольку значение не возвращается, то и оператор return не требуется.

Вот еще один пример использования функции типа void:

Второй вызов функции returnNothing() даже не скомпилируется. Функция returnNothing() имеет тип возврата void, который означает, что эта функция не возвращает значения. Однако функция main() пытается отправить это значение (которое не возвращается) в std::cout для вывода. std::cout не может обработать этот случай, так как значения на вывод не предоставлено. Следовательно, компилятор выдаст ошибку. Вам нужно будет закомментировать эту строку, чтобы компиляция прошла успешно.

Возврат значений функцией main()

Почему нужно возвращать значения обратно в операционную систему? Дело в том, что возвращаемое значение функции main() является кодом состояния, который сообщает операционной системе об успешном или неудачном выполнении программы. Обычно, возвращаемое значение 0 (ноль) означает что всё прошло успешно, тогда как любое другое значение означает неудачу/ошибку.

Обратите внимание, по стандартам языка C++ функция main() должна возвращать целочисленное значение. Однако, если вы не укажете return в конце функции main(), компилятор возвратит 0 автоматически, если никаких ошибок не будет. Но рекомендуется указывать return в конце функции main() и использовать тип возврата int для функции main().

Еще о возвращаемых значениях

Во-вторых, когда процессор встречает в функции оператор return, он немедленно выполняет возврат значения обратно в caller и точка выполнения также переходит в caller. Любой код, который находится за оператором return в функции — игнорируется.

Функция может возвращать только одно значение через return обратно в caller. Это может быть либо число (например, 7 ), либо значение переменной, либо выражение (у которого есть результат), либо определенное значение из набора возможных значений.

Но есть способы обойти правило возврата одного значения, возвращая сразу несколько значений, но об этом детально мы поговорим на соответствующем уроке.

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

Повторное использование функций

Одну и ту же функцию можно вызывать несколько раз, даже в разных программах, что очень полезно:

Источник

Форум

Справочник

Чем заменить return в c. Смотреть фото Чем заменить return в c. Смотреть картинку Чем заменить return в c. Картинка про Чем заменить return в c. Фото Чем заменить return в c

Чтобы выйти из цикла можно использовать break

В функции можно использовать return без выражения справа.

Чтобы во вложенном цикле выйти из внешнего можно использовать break с меткой

Вопрос как из вложенной функции завершить внешнюю

Сообщение от Niar
Вопрос как из вложенной функции завершить внешнюю

Ну, почему? Возможны варианты, когда из фунарга удобно завершить и саму функцию (например, в Ruby для таких случаев предусмотрены две конструкции): http://javascript.ru/blog/Dmitry-A.-. unarg-i-returnСообщение от x-yuriхорошо, а можно практический пример?

Там же в статье был:

Dmitry A. Soshnikov,
че-та я тоже пример не понял.

Сообщение от x-yuriну так здесь нету никакого завершения внешней функции из вложенной.Сообщение от KolyajDmitry A. Soshnikov,
че-та я тоже пример не понял.
А почему должен быть 2?

Нет, не должен, конечно. Для ES должен быть, правильно, null. Но вопрос в том, что иногда это может быть удобно, и, что в других языках предусмотрены для этого конструкции.

Вот этот раздел: http://en.wikipedia.org/wiki/Closure. in_sema ntics (там пониже как раз примеры на Ruby с разными вариациями return-a приводится)

Но речь идёт только о возможном завершении стека вызова (когда контексты существуют); и в Ruby можно сделать ошибку return-a, когда он не сможет определить, в какой контекст возвращать.

Источник

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

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