, принимающий адрес временного объекта

20

§5.3.1 Унарные операторы, раздел 3

  

Результат унарного & amp; оператор является указателем на его операнд. Операнд должен быть lvalue или квалифицированным идентификатором.

Что именно означает «должно быть» в этом контексте? Означает ли это, что ошибка заключается в временном адресе? Мне просто интересно, потому что g ++ дает мне предупреждение, тогда как goau отказывается компилировать следующую программу:

#include <string>

int main()
{
    &std::string("test");
}

g ++ предупреждение : taking address of temporary

Перейти ошибка : expression must be an lvalue or a function designator

Кто-нибудь имеет компилятор Microsoft или другие компиляторы и может протестировать эту программу, пожалуйста? Спасибо заранее.

    
задан fredoverflow 17.02.2010 в 13:51
источник
  • это интересно. У меня нет опыта работы с приводом, но мне интересно, запутан ли он из-за шаблона? Что произойдет, если вы просто попробуете что-то вроде & array [0]; где array - некоторый созданный массив? –  Casey 17.02.2010 в 13:58
  • & Casey & array [0] совершенно легально - массив [0] является значением lvalue –  Feb 17 '10 at 13:00 17.02.2010 в 14:00

6 ответов

24

Слово «должно» на стандартном языке означает строгое требование. Итак, да, ваш код плохо сформирован (это ошибка), потому что он пытается применить оператор адреса к не-lvalue.

Однако проблема здесь не в попытке получить адрес временного . Проблема опять-таки заключается в адресе non-lvalue . Временный объект может быть lvalue или non-lvalue в зависимости от выражения, которое создает это временное или обеспечивает доступ к этому временному. В вашем случае у вас есть std::string("test") - функциональный стиль, отлитый от не ссылочного типа, который по определению производит не-lvalue. Отсюда ошибка.

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

const std::string &r = std::string("test");
&r; // this expression produces address of a temporary

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

    
ответ дан AnT 17.02.2010 в 16:29
  • +1 для разницы rvalue и временных. Люди часто делают их равными, но их совсем нет. Общим примером являются объекты исключений, которые являются lvalues ​​и могут быть связаны с T & в предложении catch. –  Johannes Schaub - litb 19.02.2010 в 14:26
  • Фактически, сам Стандарт, по-видимому, неправильно использует термин «временный», если я не ошибаюсь. В нем говорится, что временная привязка к функции return должна быть уничтожена после возвращения функции. Однако это означает, что структура A {A & ref () {i ++; return * this; } int i; }; int main () {A (). ref (). ref (); } вызывает неопределенное поведение, потому что после первого ref () объект больше не существует. Он не считает, что рассматриваются только такие объекты, которые еще не были привязаны к ссылке (включая параметр неявного объекта). –  Johannes Schaub - litb 19.02.2010 в 14:46
  • @ JohannesSchaub-litb «В нем говорится, что временная привязка к возврату функции должна быть уничтожена после возвращения функции». Кажется, что временные и rvalue используются, как если бы они были синонимами. –  curiousguy 25.12.2011 в 23:51
  • @ JohannesSchaub-litb «Общим примером являются объекты исключений» Вы уверены, что объект исключения является временным? Это звучит неправильно. –  curiousguy 25.12.2011 в 23:53
  • @curiousguy: Объект исключения всегда является временным, т. е. всякий раз, когда вы что-то бросаете, на самом деле это временная копия этого «чего-то», который бросается. Это имеет смысл для меня, поскольку жизнь объекта объекта исключений управляется неявно за кулисами. Компилятор должен владеть им, чтобы иметь необходимую свободу для управления им. Таким образом, он создает свою собственную копию. Конечно, вы можете бросать указатели на объекты вместо реальных объектов, и в этом случае вы сохраните право собственности на объект. Но я бы сказал, что это не очень хорошая практика. –  AnT 26.12.2011 в 07:32
Показать остальные комментарии
4

Когда слово «должно» используется в стандарте C ++, это означает «нужно от боли смерти» - если реализация не подчиняется этому, он ошибочен.

    
ответ дан anon 17.02.2010 в 13:56
  • -1. На самом деле это относится только к тем утверждениям, которые «реализация должна делать X». Заявления в форме «входной код должен делать X», это означает «нужно боль от диагностики». –  MSalters 17.02.2010 в 16:21
  • @MSalters Должен по причине боли смерти выдать диагностику. –  Feb 17 '10 at 15:24 17.02.2010 в 16:24
  • @MSalters И BTW, я всегда думал, что это была сомнительная практика, чтобы ответить на вопрос, на который вы сами сами отвечаете. –  Feb 17 '10 at 15:32 17.02.2010 в 16:32
  • Я не понимаю, почему. Если вы считаете, что ответ неверен, его следует отключить независимо от того, написал ли вы ответ самостоятельно. Я думаю, мы достаточно зрелы, чтобы справиться с этим, не так ли? Или люди действительно серьезно относятся к репутации? –  jalf 17.02.2010 в 16:41
  • Посмотрите, точка SO должна действовать как хранилище ответов. Обычно есть несколько ответов, и как вы (как более поздний читатель) выбираете разумные? Голосование призвано подчеркнуть хорошие. Я ответил явно, потому что я нашел наивысшего проголосовавшего неверным, и по той же причине я отказался от него. –  MSalters 17.02.2010 в 16:45
Показать остальные комментарии
3

Это разрешено в MSVC с опцией устаревших / Ze (расширения). Это было разрешено в предыдущих версиях MSVC. Он генерирует диагностику с включенными предупреждениями:

  

предупреждение C4238: используется нестандартное расширение: класс rvalue используется как lvalue.

Если параметр / Za не используется (соблюдение совместимости ANSI), выполните следующие действия:

  

ошибка C2102: '& amp;' требуется l-значение

    
ответ дан Hans Passant 17.02.2010 в 14:03
1

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

Таким образом, в этом конкретном случае соответствующий компилятор должен давать диагностику, если принимается адрес rvalue. Оба компилятора делают, поэтому они соответствуют друг другу в этом отношении.

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

    
ответ дан MSalters 17.02.2010 в 16:19
0

&std::string("test"); запрашивает адрес возвращаемого значения вызова функции (мы будем игнорировать как несущественный факт, что эта функция является ctor). У него не было адреса, пока вы его не присвоили. Следовательно, это ошибка.

    
ответ дан James Curran 17.02.2010 в 14:05
  • Вы можете, конечно, взять адрес возвращаемых значений функции вызова, если они lvalues. –  Feb 17 '10 at 13:08 17.02.2010 в 14:08
  • Но если вы вызываете функцию, разве это не определение rvalue? –  TMN 17.02.2010 в 14:21
  • @TMN Нет - на C ++ вы можете вернуть ссылку, которая является lvalue. Вот как работают такие вещи, как operator [] для std :: vector. –  Feb 17 '10 at 13:28 17.02.2010 в 14:28
  • @James Curran: Неверно. Это не вызов функции. Это функциональный стиль. И вы можете взять адрес результата приведения (а также результата вызова функции), если это значение lvalue. Ссылка, например, всегда является значением lvalue. –  AnT 17.02.2010 в 16:35
-1

Я не эксперт по стандартам, но это, безусловно, звучит как ошибка для меня. g ++ очень часто дает предупреждение только для вещей, которые действительно являются ошибками.

    
ответ дан Hans W 17.02.2010 в 13:58