C ++ ссылки и константные указатели в C / C ++ - PullRequest
10 голосов
/ 21 ноября 2010

Недавно, когда я объяснял кому-то основное различие между указателями и ссылками (в контексте программирования на C ++), я рассказывал обычные объяснения, в которых говорится о различных соглашениях о передаче аргументов функций - вызов по значению, вызов по указателю, вызов по ссылке и вся связанная теория о ссылках.

Но затем я подумал, что бы ни делала ссылка C + с точки зрения передачи аргументов, (Позволяет эффективный для памяти способ передачи больших структур / объектов, в то же время сохраняет его безопасным, не позволяя вызываемому пользователю изменять какие-либо переменные переданного объекта для справки, если этого требует наш дизайн)

Константный указатель в C достиг бы того же самого, например. Если нужно передать указатель структуры, скажем struct mystr * ptr, приведя указатель структуры как константу -

func(int,int,(const struct mystr*)(ptr));

ptr не будет своего рода эквивалентом ссылки?

  1. Будет ли это работать не так, как было бы эффективно для памяти, если бы не реплицировать структуру (передача по указателю), а также было бы безопасно, если бы запрещались любые изменения полей структуры из-за того, что она передается как константный указатель.

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

  2. Если да, то какой сценарий варианта использования в C ++ нуждается в ссылках. Какие-либо конкретные преимущества ссылок и связанные с этим недостатки?

спасибо.

-AD

Ответы [ 3 ]

17 голосов
/ 21 ноября 2010

Вы можете привязать константную ссылку к значению:

void foo(const std::string& s);

foo(std::string("hello"));

Но нельзя передать адрес значения:

void bar(const std::string* s);

bar(&std::string("hello"));   // error: & operator requires lvalue

В язык введены ссылки для поддержки перегрузки операторов. Вы хотите иметь возможность сказать a - b, а не &a - &b. (Обратите внимание, что последний уже имеет значение: вычитание указателя.)

Ссылки в основном поддерживают передача по ссылке , указатели преимущественно поддерживают ссылочная семантика . Да, я знаю, это различие не всегда ясно в C ++.

3 голосов
/ 21 ноября 2010

Существует два типичных сценария использования:

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

Второе: ссылки используются только в сочетании с ключевым словом const, поскольку синтаксис вызова предлагает читателю семантику передачи по значению, которая по определению постоянна. Тогда указатели используются только для аргументов, которые могут быть изменены вызываемым пользователем.

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

0 голосов
/ 21 ноября 2010

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

То, что ссылка не позволяет вызываемой функции, - это изменение объекта, на который ссылается ссылка, или арифметика указателя на ссылку.

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

// declaration
void bar ( const Foo& );

// use
bar ( Foo() );

Но не сразу очевидно, что объект Foo в них имеет продолжительность жизни, превышающую длину вызова функции:

// declaration
void bar ( const Foo* );

// use
Foo temp;
bar ( &temp );

// cast to avoid warning about taking address of temporary 
bar ( &static_cast<const Foo&>( Foo() ) );  

// helper function to same effect 
template<typename T> const T* address_of ( const T& t) { return &t; }

bar ( address_of ( Foo() ) );

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

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

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