Почему ссылки не reseatable в C++

Нет, нет способа сделать это. Вместо этого вы можете переопределить ваши методы LOG, но они, вероятно, должны будут принимать части как отдельные параметры (т.е. LOG.info("It went {}", distance) или LOG.info { myformat("It went {}", distance) }). Вам нужно решить, хотите ли вы компромисса.

Единственный способ работы LOG.info { "It went ${distance}" }, который я вижу, - найти числа в интерполированной строке с помощью регулярных выражений и заменить их. Что довольно уродливо и относительно медленно.

68
задан TheFogger 8 April 2009 в 08:47
поделиться

13 ответов

Причина, что C++ не позволяет Вам снова переплетать ссылки, приведена в "Дизайне Stroustrup и Эволюции C++":

Не возможно изменить то, к чему относится ссылка после инициализации. Таким образом, после того как ссылка C++ инициализируется, это не может быть сделано относиться к другому объекту позже; это не может быть восстановление. Я имел в прошлом, укушенный ссылками Algol68 где r1=r2 может или присвоиться через r1 к упомянутому объекту или присваивают новое ссылочное значение r1 (повторное переплетение r1) в зависимости от типа r2. Я хотел избежать таких проблем в C++.

88
ответ дан Michael Burr 24 November 2019 в 14:09
поделиться

Поскольку иногда вещами не должен быть re-pointable. (Например, ссылка на Singleton.)

Поскольку замечательно в функции знать, что Ваш аргумент не может быть нулевым.

Но главным образом, потому что это позволяет использованию иметь что-то, что действительно является указателем, но которое действует как локальный объект значения. C++ очень старается, чтобы заключить Stroustrup в кавычки, заставить экземпляры класса "сделать как ints d". Передача интервала vaue является дешевой, потому что интервал fitss в машину регистрируется. Классы часто больше, чем ints, и передача их значением имеет значительные издержки.

Способность передать указатель (который часто является размером интервала или возможно двумя ints), который похож" на объект значения, позволяет нам писать более чистый код, без "детали реализации" разыменовывает. И, наряду с перегрузкой оператора, это позволяет нам писать, что классы используют синтаксис, подобный синтаксису, используемому с ints. В частности, это позволяет нам писать шаблонные классы с синтаксисом, к которому можно одинаково относиться примитивный, как ints и классы (как класс Комплексного числа).

И, с оператором, перегружающимся особенно, существуют места, были, мы должны возвратить объект, но снова, намного более дешево возвратить указатель. Oncve снова, возвращая ссылку наш ".

И указатели тверды. Не для Вас, возможно, и не любому, который понимает, указатель является просто значением адреса памяти. Но вспоминая мой класс CS 101, они сбили с толку много студентов.

char* p = s; *p = *s; *p++ = *s++; i = ++*p;

может сбивать с толку.

Heck, после 40 лет C, люди все еще не могут даже согласиться, должно ли объявление указателя быть:

char* p;

или

char *p;
0
ответ дан tpdi 24 November 2019 в 14:09
поделиться

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

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

0
ответ дан dmckee 24 November 2019 в 14:09
поделиться

Ссылки C++ могут иногда вынуждаться быть 0 с некоторыми компиляторами (это - просто плохая идея сделать так*, и это нарушает стандарт*).

int &x = *((int*)0); // Illegal but some compilers accept it

Править: по словам различных людей, которые знают стандарт намного лучше, чем я, вышеупомянутый код производит "неопределенное поведение". По крайней мере в некоторых версиях GCC и Visual Studio, я видел, что это делает ожидаемую вещь: эквивалент установки в NULL указателя (и причины Исключение нулевого указателя при доступе).

2
ответ дан Mr Fooz 24 November 2019 в 14:09
поделиться

Это, вероятно, менее сбивало бы с толку для именования ссылок C++ "псевдонимами"? Как другие упомянули, ссылки в C++ должны быть то, хотя из как переменная они обращаются к, не как указатель/ссылка на переменную. По сути, я не могу думать о серьезном основании, они должны быть восстановлены.

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

4
ответ дан snemarch 24 November 2019 в 14:09
поделиться

reseatable ссылка была бы функционально идентична указателю.

Относительно nullability: Вы не можете гарантировать, что такая "reseatable ссылка" является непустой во время компиляции, таким образом, любой такой тест должен был бы произойти во времени выполнения. Вы могли достигнуть этого сами путем записи шаблона класса стиля интеллектуального указателя, который выдает исключение, когда инициализировано или присвоено ПУСТОЙ УКАЗАТЕЛЬ:

struct null_pointer_exception { ... };

template<typename T>
struct non_null_pointer {
    // No default ctor as it could only sensibly produce a NULL pointer
    non_null_pointer(T* p) : _p(p) { die_if_null(); }
    non_null_pointer(non_null_pointer const& nnp) : _p(nnp._p) {}
    non_null_pointer& operator=(T* p) { _p = p; die_if_null(); }
    non_null_pointer& operator=(non_null_pointer const& nnp) { _p = nnp._p; }

    T& operator*() { return *_p; }
    T const& operator*() const { return *_p; }
    T* operator->() { return _p; }

    // Allow implicit conversion to T* for convenience
    operator T*() const { return _p; }

    // You also need to implement operators for +, -, +=, -=, ++, --

private:
    T* _p;
    void die_if_null() const {
        if (!_p) { throw null_pointer_exception(); }
    }
};

Это могло бы быть полезно при случае - функция, берущая a non_null_pointer<int> параметр, конечно, передает больше информации вызывающей стороне, чем делает функциональное взятие int*.

5
ответ дан j_random_hacker 24 November 2019 в 14:09
поделиться

Ссылка не является указателем, она может быть реализована как указатель в фоновом режиме, но его базовое понятие не эквивалентно указателю. Ссылка нужно посмотреть на подобный это *is* объект это относится к. Поэтому Вы не можете изменить его, и это не может быть ПУСТЫМ.

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

Я думаю парасдвиг C++, FAQ на ссылках говорит это лучше всего:

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

и снова в FAQ 8.5:

В отличие от указателя, когда-то ссылка связывается с объектом, она не может быть "переустановлена" к другому объекту. Сама ссылка не является объектом (она не имеет никаких идентификационных данных; взятие адреса ссылки дает Вам адрес референта;помните: ссылка является своим референтом).

5
ответ дан Brian R. Bondy 24 November 2019 в 14:09
поделиться

Поскольку затем у Вас не было бы reseatable типа, который не может быть 0. Если, Вы не включали 3 типа ссылок/указателей. Который просто усложнил бы язык для очень небольшого количества усиления (И затем почему бы не добавить 4-й тип также? Ссылка Non-reseatable, которая может быть 0?)

Лучший вопрос может быть, почему Вы хотели бы, чтобы ссылки были reseatable? Если бы они были, который сделал бы их менее полезными в большом количестве ситуаций. Это мешало бы компилятору делать анализ псевдонима.

Кажется, что главная причина, ссылки в Java или C# reseatable, состоит в том, потому что они делают работу указателей. Они указывают на объекты. Они не псевдонимы для объекта.

Что должно эффект следующего быть?

int i = 42;
int& j = i;
j = 43;

В C++ сегодня, с non-reseatable ссылками, это просто. j является псевдонимом, поскольку я, и я заканчиваю со значением 43.

Если бы ссылки были reseatable, то третья строка связала бы ссылку j с другим значением. Это больше не искажало бы i, но вместо этого целочисленные литеральные 43 (который не допустим, конечно). Или возможно более простое (или по крайней мере синтаксически допустимый) пример:

int i = 42;
int k = 43;
int& j = i;
j = k;

С reseatable ссылками. j указал бы на k после оценки этого кода. С non-reseatable ссылками C++, j неподвижные точки мне, и мне присваивают значение 43.

Делание ссылок reseatable изменения семантика языка. Ссылка больше не может быть псевдонимом для другой переменной. Вместо этого это становится отдельным типом значения с его собственным оператором присваивания. И затем одно из наиболее распространенных использований ссылок было бы невозможно. И ничто не было бы получено в обмен. Недавно полученная функциональность для ссылок уже существовала в форме указателей. Таким образом, теперь у нас было бы два способа сделать то же самое и никакой способ сделать то, что делают ссылки на текущем языке C++.

18
ответ дан jalf 24 November 2019 в 14:09
поделиться

В C++ часто говорится, что "ссылка является объектом". В одном смысле это верно: хотя ссылки обрабатываются как указатели, когда исходный код компилируется, ссылка предназначается для выражения объекта, который не копируется, когда функция вызвана. Так как ссылки не являются прямо адресуемыми (например, ссылки не имеют никакого адреса, и возвращает адрес объекта), семантически не имело бы смысла повторно присваивать им. Кроме того, C++ уже имеет указатели, который обрабатывает семантику сброса.

32
ответ дан Geek 24 November 2019 в 14:09
поделиться

Вы не можете сделать этого:

int theInt = 0;
int& refToTheInt = theInt;

int otherInt = 42;
refToTheInt = otherInt;

... по той же причине, почему secondInt и firstInt не имеют того же значения здесь:

int firstInt = 1;
int secondInt = 2;
secondInt = firstInt;
firstInt = 3;

assert( firstInt != secondInt );
1
ответ дан John Dibling 24 November 2019 в 14:09
поделиться

Я всегда задавался вопросом, почему они не сделали ссылочный оператор присваивания (скажите: =) для этого.

Только для действования на чьи-то нервы я написал некоторый код для изменения цели ссылки в структуре.

Нет, я не рекомендую повторить свой прием. Это повредится, если портировано к достаточно другой архитектуре.

0
ответ дан Joshua 24 November 2019 в 14:09
поделиться

The fact that references in C++ are not nullable is a side-effect of them being just an alias.

0
ответ дан hasen 24 November 2019 в 14:09
поделиться

Быть наполовину серьезным: ИМХО, чтобы сделать их немного более отличными от указателей;) Вы знаете, что вы можете написать:

MyClass & c = *new MyClass();

Если бы вы могли позже написать:

c = *new MyClass("other")

, имеет ли смысл иметь какие-либо ссылки наряду с указателями?

MyClass * a =  new MyClass();
MyClass & b = *new MyClass();
a =  new MyClass("other");
b = *new MyClass("another");
0
ответ дан 24 November 2019 в 14:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: