Обновлено: этот вопрос больше касается языковой инженерии, чем самого C++. Я использовал C++ в качестве примера, чтобы показать, что я хочу, в основном потому, что использую его ежедневно. Я не хотел знать, как это работает на C++, но начал обсуждение того, как это сделать мог.
Это не то, как это работает сейчас, это то, как я желание это могло бы сделать, и это наверняка нарушило бы совместимость с C, но я думаю, что это именно то, о чем extern "C".
Я имею в виду, что в каждой функции или методе, которые вы объявляете прямо сейчас, вы должны явно указать, что объект будет отправлен по ссылке с префиксом оператора ссылки на нем. Я хочу, чтобы каждый тип, не относящийся к POD, автоматически отправлялся по ссылке, потому что я использую это много, фактически для каждого объекта, размер которого превышает 32 бита, и это почти каждый мой класс.
Давайте проиллюстрируем, как это происходит сейчас, предположим, что а, б и c являются классами:
class example {
public:
int just_use_a(const a &object);
int use_and_mess_with_b(b &object);
void do_nothing_on_c(c object);
};
Теперь то, что я желаю:
class example {
public:
int just_use_a(const a object);
int use_and_mess_with_b(b object);
extern "C" void do_nothing_on_c(c object);
};
Теперь do_nothing_on_c () может вести себя так же, как сегодня.
Это было бы интересно, по крайней мере, для меня, кажется намного более ясным, а также, если вы знать, каждый параметр, не относящийся к POD, приходит по ссылке, я считаю, что ошибки будут такими же, как если бы вам пришлось явно объявить его.
Другая точка зрения на это изменение, от кого-то из C, оператор ссылки кажется мне способом получить переменную адрес, что я использовал для получения указателей. Я имею в виду, что это один и тот же оператор, но с разной семантикой в разных контекстах, разве это не кажется вам немного неправильным?
Точно. Этот вопрос больше касается языковой инженерии, чем C++. Прошу прощения, если я использую C++ в качестве примера, но это язык, который я использую чаще всего, поэтому, если бы я хотел сделать один C++, был бы моей базой.





Я искренне думаю, что вся эта идея передачи по значению / передаче по ссылке в C++ вводит в заблуждение. Все передается по значению. У вас есть три случая:
Где вы передаете локальную копию переменной
void myFunct(int cantChangeMyValue)
Где вы передаете локальную копию указателя на переменную
void myFunct(int* cantChangeMyAddress) {
*cantChangeMyAddress = 10;
}
Если вы передаете «ссылку», но с помощью магии компилятора это так же, как если бы вы передавали указатель и просто разыменовывали его каждый раз.
void myFunct(int & hereBeMagic) {
hereBeMagic = 10; // same as 2, without the dereference
}
Я лично считаю, что гораздо менее запутанно помнить, что все передается по ценности. В некоторых случаях это значение может быть адресом, который позволяет вам изменять вещи вне функции.
То, что вы предлагаете, не позволит программисту сделать номер 1. Я лично считаю, что было бы плохой идеей отказаться от этой возможности. Один из основных плюсов C / C++ - мелкозернистое управление памятью. Передача всего по ссылке - это просто попытка сделать C++ более похожим на Java.
Если вы начнете переопределять устоявшееся значение передачи по значению и передачи по ссылке, это то, что я считаю вводящим в заблуждение.
Сценарий 3 совсем не эквивалентен сценарию 2 (без разыменования). Вы не можете передать пустую ссылку. (-1)
Да, я считаю, что это довольно сбивающая с толку перегрузка.
Вот что Microsoft говорит о ситуации:
Do not confuse reference declarations with use of the address-of operator. When & identifier is preceded by a type, such as int or char, then identifier is declared as a reference to the type. When & identifier is not preceded by a type, the usage is that of the address-of operator.
Я не очень хорошо разбираюсь в C или C++, но у меня возникают большие головные боли, разбирая различные варианты использования * и & на обоих языках, чем я кодирую на ассемблере.
На самом деле это не отличается от использования * в объявлении и * в операторе. Вы можете справиться с этим в C. C++ более ортогонален, поскольку вы можете использовать как &, так и * в объявлении и в качестве оператора.
Вариант компилятора, который полностью меняет значение части кода, мне кажется плохой идеей. Либо воспользуйтесь синтаксисом C++, либо найдите другой язык.
Лучший совет - выработать привычку думать о том, чего вы действительно хотите. Передача по ссылке удобна, когда у вас нет конструктора копирования (или вы не хотите его использовать), и это дешевле для больших объектов. Однако тогда мутации параметра ощущаются вне класса. Вместо этого вы можете передать ссылку const - тогда мутаций нет, но вы не сможете вносить локальные изменения. Передавайте константу по значению для дешевых объектов, которые должны быть доступны только для чтения в функции, и передавайте неконстантные по значению, если вам нужна копия, в которую вы можете вносить локальные изменения.
Каждая перестановка (по значению / по ссылке и константная / неконстантная) имеет важные различия, которые определенно не эквивалентны.
Когда вы переходите по значению, вы копируете данные в стек. Если у вас есть оператор =, определенный для структуры или класса, который вы ему передаете, он выполняется. Я знаю, что не существует директивы компилятора, которая смоет бессмысленную неразбериху неявного языка, которую предложенное изменение вызвало бы по своей сути.
Распространенной передовой практикой является передача значений по константной ссылке, а не только по ссылке. Это гарантирует, что значение не может быть изменено в вызывающей функции. Это один из элементов константно-правильной кодовой базы.
Кодовая база, полностью верная по константам, идет еще дальше, добавляя константу в конец прототипов. Рассматривать:
void Foo::PrintStats( void ) const {
/* Cannot modify Foo member variables */
}
void Foo::ChangeStats( void ) {
/* Can modify foo member variables */
}
Если вам нужно передать объект Foo в функцию с префиксом const, вы можете вызвать PrintStats (). Компилятор выдает ошибку при вызове ChangeStats ().
void ManipulateFoo( const Foo &foo )
{
foo.PrintStats(); // Works
foo.ChangeStats(); // Oops; compile error
}
Я бы предпочел больше не злоупотреблять ссылками, делая каждый (неквалифицированный) параметр ссылкой.
Основная причина, по которой ссылки были добавлены в C++, - это для поддержки перегрузки оператора; если вам нужна семантика «передачи по ссылке», у C был вполне разумный способ сделать это: указатели.
Использование указателей проясняет ваше намерение изменить значение указанного объекта, и это можно увидеть, просто посмотрев на вызов функции, вам не нужно смотреть на объявление функции, чтобы увидеть, использует ли он ссылку.
Также см
I do want to change the argument, should I use a pointer or should I use a reference? I don't know a strong logical reason. If passing ``not an object'' (e.g. a null pointer) is acceptable, using a pointer makes sense. My personal style is to use a pointer when I want to modify an object because in some contexts that makes it easier to spot that a modification is possible.
есть что-то непонятное. когда ты сказал:
int b(b ¶m);
что ты задумал для второй «б»? ты забыл ввести тип? ты забыл написать иначе по отношению к первой «б»? Вам не кажется, что можно написать что-то вроде:
class B{/*something...*/};
int b(B& param);
С этого момента, я полагаю, вы имеете в виду то, что я пишу.
Теперь ваш вопрос: «Не думаете ли вы, что будет лучше, если компилятор будет рассматривать каждую передачу по значению не-POD как передачу по ссылке?». Первая проблема в том, что это нарушит ваш контракт. Я полагаю, вы имеете в виду передачу по CONST-ссылке, а не только по ссылке.
Теперь ваш вопрос сводится к следующему: «знаете ли вы, есть ли какая-нибудь директива компилятора, которая может оптимизировать вызов функции по значению?»
Теперь ответ - «не знаю».
b - это тип, я просто не сказал, я подумал, будет понятно, функция имеет то же имя только потому, что она возится с b, это может быть do_something_nice_with_b (b & object).
Я думаю, что C++ станет очень запутанным, если вы начнете смешивать все виды доступных параметров с их константными вариациями.
Отслеживание всех вызовов конструкторов копирования, всех перегруженных разыменований и т. д. Быстро выходит из-под контроля.
Вы поняли, что нужно упростить синтаксис и использовать одну конкретную семантику. Эти предлагаемые изменения - способ преодолеть этот беспорядок с множеством возможностей. Я думаю, что одним из главных критиков C++ является то, что он пытается сделать слишком много вещей.
Что ж, мне потребовалось время, чтобы снова понять вопрос (я использовал diff). Предполагается, что "extern" C "сообщает" передать его по копии, а не по ссылке, как для двух функций выше ".