2015-03-11 3 views
9

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

char *strcat(char *dst, const char *src); 

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

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

char *p = func(int i, const char *s); 

Тогда есть аргумент, что переменные стоп-копий дороги, и поэтому использовать указатели вместо этого. Но, как упомянуто here, некоторые компиляторы могут сами решить это (предполагая, что это относится и к C). Есть ли общее правило или, по крайней мере, какое-то неписаное соглашение, когда использовать тот или иной? Я оцениваю производительность выше дизайна.

+3

Звучит скорее как http://programmers.stackexchange.com/ question – cup

+0

Возвращающиеся указатели обычно приводят к проблеме управления жизненным циклом, на которую указывает объект, потому что 90% времени, pointee вновь создается функцией. – user3528438

+0

Пример с 'strcat' верен для API старого стиля. Новый код ошибки возврата: errno_t strcat_s ( char * strDestination, size_t numberOfElements, const char * strSource ) '. – i486

ответ

10

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

Это не 1980-е годы. С тех пор компиляторы стали намного умнее и действительно хорошо работают над оптимизацией кода, особенно кода, написанного четким и простым способом. Аналогичным образом, переход параметров и соглашения о возврате значений также стали довольно сложными. Простейшая модель на основе стека на самом деле не отражает реальность современного оборудования.

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

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

-2

Эмпирические правила:

  1. Если sizeof(return type) больше, чем sizeof(int), вероятно, вы должны передать его по указателю, чтобы избежать накладных расходов на копирование. Это проблема производительности. Есть несколько штрафов за разыменование указателя, поэтому есть некоторые исключения из этого правила.
  2. Если тип возврата является сложным (содержит элементы указателя), передайте его указателем. Например, копирование локального значения возврата в стек не будет копировать динамическую память.
  3. Если вы хотите, чтобы функция выделяла память, она должна вернуть указатель на вновь выделенную память. Это называется фабрикой шаблон дизайна.
  4. Если у вас есть более чем одна вещь, которую вы хотите вернуть из функции, верните ее по значению и передайте остальные указатели.
  5. Если у вас есть сложный/большой тип данных, который является как входным, так и выходным, передайте его указателем.
+1

Откуда они взялись? Я имею в виду ваши «Правила большого пальца». Не могли бы вы представить ссылки ссылки? –

+0

Мой опыт, некоторые здравый смысл и хорошие отраслевые практики. – liorda

+0

№ 5 относится к любому типу данных ... и это наименьший из неполных ответов, которые вы даете здесь .... – Pandrei

Смежные вопросы