Общий вопрос: что передать в качестве указателя в C / C ++? - PullRequest
1 голос
/ 13 мая 2011

Привет, интересно, стоит ли передавать примитивные одиночные значения, такие как int, float, double или char по указателю?Наверное, это не стоит !?Но если вы просто передадите все по указателю, это замедлит программу?Должны ли вы всегда просто передавать массивы в качестве указателя?Спасибо!

Ответы [ 8 ]

4 голосов
/ 13 мая 2011

Интересно, стоит ли передавать примитивные одиночные значения, такие как int, float, double или char по указателю?

Чего ты пытаешься достичь? Хотите иметь возможность писать в переданное значение? Или вам просто нужно это использовать? Если вы хотите написать в него, идиоматический способ - пройти мимо ссылка . Если вам не нужно писать в него, вам лучше избегать любого риска, что вы напишите в него случайно и передадите по значению. Передача по значению создаст копию переменной для локального использования. (кроме того, если вы не хотите делать копию и хотите получить определенный уровень безопасности, вы можете пройти мимо const reference )

Но если вы просто передадите все по указателю, это замедлит работу программы?

Трудно сказать. Зависит от многих вещей. И в передаче по значению и в передаче по ссылке (или указателю) вы создаете новый тип примитива. При передаче по значению вы делаете копию. При передаче по ссылке / указателю вы передаете адрес оригиналу. В последнем случае, однако, вам требуется дополнительная загрузка памяти, которая может или не может быть кэширована. Очень сложно сказать 100%, не измеряя его.

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

Должны ли вы всегда просто передавать массивы в качестве указателя?

С это .

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

Для передачи массива:

 int foo(int bar[], unsigned int length)
 {
       // do stuff with bar but don't go past length
 }

Я бы рекомендовал избегать массивов и использовать std :: vector, который имеет более понятную семантику копирования.

3 голосов
/ 13 мая 2011

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

Однако указатели часто являются «шириной шины», то есть процессор может отправлять все значение сразу, а не «сдвигать» значения для отправки по шине. Таким образом, возможно, указатели передаются на шину быстрее, чем меньшие типы (например, char). Вот почему старые компьютеры Cray делали свои char значения 32 битами (ширина шины в то время).

2 голосов
/ 13 мая 2011

При работе с большими объектами (такими как классы или массивы) передача указателя происходит быстрее, чем копирование всего объекта в стек. Это относится к ООП, например

2 голосов
/ 13 мая 2011

Найдите в своем любимом учебнике по С ++ обсуждение "выходных параметров".


Некоторые преимущества использования указателя для выходных параметров вместо ссылки:

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

  • Совместимость с C (что важно для заголовка вашего вопроса)

  • Используемые другими языками функции, экспортируемые из общей библиотеки или DLL, не должны использовать только функции C ++, такие как ссылки.

1 голос
/ 13 мая 2011

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

// which version of factorial is shorter and easy to use?

int factorial_1 (int* number)
{
  if ((*number) <= 1)
    return 1;
  int tmp = (*number) - 1;
  return (*number) * factorial_1 (&tmp);
}

// Usage:
int r = 10;
factorial_1 (&r); // => 3628800


int factorial_2 (int number)
{
  return (number <= 1) ? 1 : (number * factorial_2 (number - 1));
}

// Usage:
// No need for the temporary variable to hold the argument.
factorial_1 (10); // => 3628800

Отладка становится сложной, поскольку вы не можете сказать, когда и где может измениться значение объекта:

int a = 10;
// f cound modify a, you cannot guarantee g that a is still 10.
f (&a); 
g (&a);

Предпочитаю класс vector над массивами. Он может расти и уменьшаться по мере необходимости и отслеживает его размер. Способ доступа к элементам vector совместим с массивами:

int add_all (const std::vector<int>& vec)
{
    size_t sz = vec.size ();
    int sum = 0;
    for (size_t i = 0; i < sz; ++i)
        sum += vec[i]; 
}
1 голос
/ 13 мая 2011

Реального ответа на ваш вопрос нет, кроме нескольких правил, которые я склонен иметь в виду: char - это 8 байт, а указатель - 4 байта, поэтому никогда не передавайте один символ в качестве указателя. после того как такие вещи, как int и float имеют тот же размер, что и указатель, но на указатель необходимо ссылаться, чтобы технически это заняло больше времени

если перейти к ассемблеру Pentium I386:

загрузка значения в регистр параметра "a" в C, который является целым числом:

movl 8(%ebp),%eax  

то же самое, но передается как указатель:

movl 8(%ebp),%eax
movl (%eax),%eax

Необходимость разыменования указателя требует другой операции с памятью, поэтому теоретически (не уверен, что это в реальной жизни) передача указателей длиннее ... После проблемы с памятью. Если вы хотите эффективно кодировать весь составной тип (класс, структура, массивы ...), он должен быть передан по указателю. Просто представьте, что выполняете рекурсивную функцию с типом 16 байтов, который передается при копировании для 1000 вызовов, что составляет 16000 байтов в стеке (вы действительно не хотите этого делать? :))

Итак, чтобы сделать его кратким и понятным: посмотрите на размер вашего типа, если он больше, чем указатель, передайте его указателем, иначе передайте его копией ...

1 голос
/ 13 мая 2011

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

Обратите внимание, что предотвращение копирования также может быть выполнено с помощью copy-elision, поэтому вы должны быть очень осторожны, чтобы не попасть в ловушку преждевременной оптимизации. Это может на самом деле сделать ваш код медленнее.

0 голосов
/ 13 мая 2011

НЕТ , единственный раз, когда вы передаете неконстантную ссылку , это если функция требует выходного параметра.

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