Каким образом ссылка неконстанты не может связать с временным объектом?

Прекратите использовать SQL/плюс, я настоятельно рекомендую Разработчик пуазейли / Разработчик SQL , это намного больше, чем инструмент SQL.

p.s. Некоторые люди предпочитают ЖАБА .

220
задан curiousguy 6 December 2011 в 03:23
поделиться

7 ответов

Из этой статьи блога Visual C ++ о ссылках на rvalue :

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

В принципе, вы не должны пытаться изменять временные объекты по той самой причине, что они являются временными объектами и умрут в любой момент. Причина, по которой вам разрешено вызывать неконстантные методы, заключается в том, что вы можете делать некоторые «глупые» вещи, если вы знаете, что делаете, и четко об этом говорите (например, используя reinterpret_cast). Но если вы привяжете временную ссылку к неконстантной ссылке, вы можете продолжать передавать ее «вечно», просто чтобы ваши манипуляции с объектом исчезли, потому что где-то по пути вы полностью забыли, что это было временным.

На вашем месте я бы переосмыслил структуру своих функций. Почему g () принимает ссылку, изменяет ли он параметр? Если нет, сделайте это константной ссылкой, если да, почему вы пытаетесь передать ему временное значение, вам все равно? Как временно вы изменяете? Почему getx () все равно возвращается временно? Если вы поделитесь с нами своим реальным сценарием и тем, что вы пытаетесь достичь, вы можете получить несколько хороших советов о том, как это сделать.

Противоречие языку и обман компилятора редко решают проблемы - обычно они создают проблемы.


] Изменить: ответы на вопросы в комментарии: 1) X& x = getx().ref(); // OK when will x die? - я не знаю и мне все равно, потому что это именно то, что я имею в виду, говоря «идти против языка». В языке говорится, что «временные объекты умирают в конце оператора, если они не привязаны к константной ссылке, и в этом случае они умирают, когда ссылка выходит за пределы области видимости». Применяя это правило, кажется, что x уже мертв в начале следующего оператора, поскольку он не привязан к ссылке const (компилятор не знает, что возвращает ref ()). Однако это всего лишь предположение.

2) Я четко сформулировал цель: вам не разрешено изменять временные файлы, потому что это просто не имеет смысла (игнорируя ссылки C ++ 0x rvalue). На вопрос «тогда почему мне разрешено вызывать неконстантные члены?» хороший, но у меня нет лучшего ответа, чем тот, который я уже сказал выше.

3) Что ж, если я прав насчет x в X & x = getx (). Ref (); умирает в конце оператора, проблемы очевидны.

В любом случае, судя по вашему вопросу и комментариям, я не думаю, что даже эти дополнительные ответы вас удовлетворит. Вот последняя попытка / резюме: комитет C ++ решил, что нет смысла изменять временные файлы, поэтому они запретили привязку к неконстантным ссылкам. Может быть, была задействована какая-то реализация компилятора или исторические проблемы, я не знаю. Потом, возник какой-то конкретный случай, и было решено, что, несмотря ни на что, они все же разрешат прямую модификацию через вызов неконстантного метода. Но это исключение - вам обычно не разрешается изменять временные файлы. Да, C ++ часто бывает таким странным.

95
ответ дан 23 November 2019 в 04:08
поделиться

Зачем вам вообще X & x = getx (); ? Просто используйте X x = getx ();

4
ответ дан 23 November 2019 в 04:08
поделиться

Злой обходной путь связан с ключевым словом "изменяемый". На самом деле быть злом оставлено как упражнение для читателя. Или см. Здесь: http://www.ddj.com/cpp/184403758

4
ответ дан 23 November 2019 в 04:08
поделиться

То, что вы показываете, это то, что цепочка операторов разрешена.

 X& x = getx().ref(); // OK

Выражение - 'getx (). Ref ();' и это выполняется до завершения перед присвоением 'x'.

Обратите внимание, что getx () возвращает не ссылку, а полностью сформированный объект в локальный контекст. Объект временный, но он не const, что позволяет вам вызывать другие методы для вычисления значения или возникновения других побочных эффектов.

// It would allow things like this.
getPipeline().procInstr(1).procInstr(2).procInstr(3);

// or more commonly
std::cout << getManiplator() << 5;

Посмотрите в конце этого ответа, чтобы увидеть лучший пример этого.

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

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

x& = const_cast<x&>(getX());

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

Таким образом, единственный оставшийся вопрос заключается в том, почему стандарт не разрешает ссылку на временные объекты для продления срока службы объекта за пределами конца оператора?

Я считаю, что это потому, что в этом случае компилятору будет очень сложно исправить временные объекты. Хотя следующее:

int const& y = getI();

Дает вам код, который интуитивно понятен и понятен.

Если вы хотите изменить значение, вы должны возвращать значение переменной. Если вы пытаетесь избежать затрат на копирование объекта обратно из функции (поскольку кажется, что объект скопирован обратно (технически это так)). Тогда не беспокойтесь, компилятор очень хорош в «Оптимизация возвращаемого значения»

16
ответ дан 23 November 2019 в 04:08
поделиться

На самом деле ваш сценарий не сильно соответствует блокировке - но мы все равно попробуем ;-p

Я немного изменил настройку ; вместо этого:

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

Вот код; обратите внимание, что у них нет блокировки, когда использует основание, так как это помешает другим людям присоединиться к очереди для Pulse .

В действительности, мы могли бы сделать ] все из этого с только блокировка (без использования Pulse вообще), и просто используйте стандартное поведение блокировки. к непостоянным функциям разрешены. Например, ref () может изменить временный object. "

В вашем примере getX () не возвращает const X, поэтому вы можете вызвать ref () почти так же, как вы могли бы вызвать X (). ref (). Вы возвращаете не const ref и, таким образом, может вызывать методы, не являющиеся константными, чего вы не можете сделать, так это присвоить ref неконстантной ссылке.

Наряду с комментарием SadSidos это делает ваши три пункта неверными.

2
ответ дан 23 November 2019 в 04:08
поделиться

В вашем коде ] getx () возвращает временный объект, так называемое «rvalue». Вы можете скопировать rvalue в объекты (также известные как переменные) или привязать их к константным ссылкам (что продлит их время жизни до конца жизни ссылки). Вы не можете привязать rvalue к неконстантным ссылкам.

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

g(getx()); // g() would modify an object without anyone being able to observe

Если вы хотите сделать это, вам придется либо сделать локальную копию либо объекта, либо привязать его к константной ссылке:

X x1 = getx();
const X& x2 = getx(); // extend lifetime of temporary to lifetime of const reference

g(x1); // fine
g(x2); // can't bind a const reference to a non-const reference

Обратите внимание, что следующий стандарт C ++ будет включать ссылки rvalue. Поэтому то, что вы называете ссылками, становится называться «ссылками lvalue». Вам будет разрешено связывать rvalue со ссылками на rvalue, и вы можете перегружать функции на "rvalue-ness":

void g(X&);   // #1, takes an ordinary (lvalue) reference
void g(X&&);  // #2, takes an rvalue reference

X x; 
g(x);      // calls #1
g(getx()); // calls #2
g(X());    // calls #2, too

Идея ссылок rvalue заключается в том, что, поскольку эти объекты все равно умрут, вы можете воспользоваться этим знанием и реализовать так называемую «семантику перемещения», определенный вид оптимизации:

class X {
  X(X&& rhs)
    : pimpl( rhs.pimpl ) // steal rhs' data...
  {
    rhs.pimpl = NULL; // ...and leave it empty, but deconstructible
  }

  data* pimpl; // you would use a smart ptr, of course
};


X x(getx()); // x will steal the rvalue's data, leaving the temporary object empty
36
ответ дан 23 November 2019 в 04:08
поделиться

Основная проблема заключается в том, что

g(getx()); //error

является логической ошибкой: g изменяет результат getx () , но у вас нет любая возможность изучить измененный объект. Если g не нужно было изменять свой параметр, тогда ему не потребовалась бы ссылка lvalue, он мог бы взять параметр по значению или по константной ссылке.

const X& x = getx(); // OK

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

Однако невозможно сделать

X& x = getx(); // error

действительным, не сделав g (getx ()) действительным , чего разработчики языка пытались избежать в первую очередь.

g(getx().ref()); //OK

действительно, потому что методы знают только о константе this , они не Не знаю, вызываются ли они по lvalue или по rvalue.

Как всегда в C ++, у вас есть обходной путь для этого правила, но вы должны сообщить компилятору, что вы знаете, что делаете, явным образом:

g(const_cast<x&>(getX()));
6
ответ дан 23 November 2019 в 04:08
поделиться
Другие вопросы по тегам:

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