Обозначение указателей в C++

169
19 июня 2022, 19:50

Здравствуйте. Есть ли какие-нибудь существенные различия между такими определениями указателя:

int* a;
int *b;

Также хотелось бы выяснить, выигрывает ли в быстродействии определение типа "указатель на указатель". Стоит ли его использовать, или это является плохим стилем? Какую альтернативу можно применить, если лучше стараться избегать такого:

int var = 123; 
int *ptrvar = &var;
int **ptr_ptrvar = &ptrvar; 
int ***ptr_ptr_ptrvar = &ptr_ptrvar;
Answer 1
  • В первом случае с точки зрения поведения разницы нет. Где ставить '*' в этом случае - это сугубо вопрос вкуса и используемого coding standard.

  • Говорить о быстродействии в таких вопросах обычно не имеет смысла, поскольку шанс того, что передача объекта по указателю станет узким местом вашего приложения, очень близок к нулю даже под платформами типа ARM.

Если, конечно, хочется пообсуждать, то делать это нужно, имея N ассемблерных листингов gcc, cl, clang и icc с разными уровнями оптимизаций, хотя у меня есть сильное подозрение, что он будет одинаков для большинства случаев.

  • Поскольку использование многоуровневой адресации (int ***ptr_ptr_ptrvar) очень сильно вредит читаемости кода, делать это следует только в случаях, когда без этого действительно не обойтись (в 99% случаев это - bad code smell).

Если вам нужно, чтобы значение переменной var изменялось в функции, передавайте ее по указателю [C99] или иногда, если удобнее, то по ссылке [C++03]. Некоторые стандарты явно запрещают передачу переменной с семантикой out по неконстантной ссылке и требуют для этого использования указателя.

Answer 2

Существенных отличий нет, скорее дело вкуса. Однако следует обратить внимание на следующий момент - несмотря на то, что указатель относится к типу (т.е. тип переменной : указатель на int, или указатель на char), запись вида :

int *a, b, c;

вовсе не будет означать, что у Вас описаны 3 указателя на int, - это 1 указатель и 2 переменных типа int.
Использование многоуровневой адресации возможно, однако уровни глубже второго (указатель на указатель) применяются крайне редко, да и IMXO, запутывают программу.

Answer 3
  1. Тип переменных

    int* a;
    int *b;
    int * c;
    int      *                   qewetrye;
    

    не различается - это всё указатели на целое.

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

Answer 4

Я бы сказал, что семантически правильной является запись:

int *a;

а не:

int* a;

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

int* a, b, c;

Не означает, что все три a, b и с являются указателями на целое. Семантически именно это и написано! Типа int* - нет! А запись:

int *a, b, c;

Не вызывает никакой иллюзии. Здесь четко и явно видно что указателем является только а.

Answer 5

Так

int*a;

и так

int   *    b;

тоже годится. Количество пробелов влияет только на размер исходного файла.

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

@Asen, искусственное "накручивание" адресов применять не надо.

По поводу быстородействия - точно не ускорит.

Answer 6
  1. Записи int* a; и int *b; эквивалентны.
  2. Разница появляется в том, что когда нужно в одну строчку объявить несколько указателей. Например:

    int* a, b, c; // a - указатель, b и с - просто целочисленные переменные int* d,*e,*f; // здесь определено три указателя: d, e, f

  3. В случае с применением конструкция typedef и #define получается интереснее.

    #define P_INT int* typedef int* PINT; P_INT d, e, f; // указатель ТОЛЬКО d. PINT a, b, c; // все три являются указателями

    Внимание, тут явная ошибка, которую стоит обходить :-) И это еще один повод не пользоваться define.

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

Answer 7
int              var  = 123;     
auto          ptrvar  = &var;    
auto      ptr_ptrvar  = &ptrvar;     
auto   ptr_ptr_ptrvar = &ptr_ptrvar; 
cout<< " var= " << ***ptr_ptr_ptrvar <<"\n";
//  обычно разыменовывание указателя очень быстрая операция. но нужно смотреть на компилер   
// если хочется передавать данные через * то лучше так:
 vector (const vector &);  // Конструктор копирования (медленный)  
 vector (vector &&);       // Конструктор переноса из временного объекта (быстрый)
READ ALSO
Boost Asio Streambuf, UDP, Передача структур данных по сети

Boost Asio Streambuf, UDP, Передача структур данных по сети

Всем привет! Когда клиент отправляет серверу(или наоборот) буфер данных сделанное с помощью boost::asio::streambuf то данные как то смещаются и на выходе...

205
Почему внедрение библиотеки не работает?

Почему внедрение библиотеки не работает?

Пытался написать код на внедрение библиотеки в только что созданный процесс, но что-то не получаетсяФункция inject возвращает true, но сама библиотека...

109
В каких случаях нужно наследоваться от std :: enable_shared_from_this и зачем это делать?

В каких случаях нужно наследоваться от std :: enable_shared_from_this и зачем это делать?

В каких случаях нужно наследоваться от std :: enable_shared_from_this и зачем это делать? Увидел в примерах boost asio наследование от enable_shared_from_this, что это...

131