Взятие адреса временного объекта

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

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

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

#include <string>

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

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

ошибка комо: expression must be an lvalue or a function designator

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

6 ответов

Решение

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

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

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

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

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

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

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

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

Если не используется опция /Za (обеспечить совместимость с ANSI), то:

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

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

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

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

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

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

Определяемое пользователем преобразование

struct String {
    std::string str;

    operator std::string*() {
        return &str;
    }
};

std::string *my_str = String{"abc"};
Другие вопросы по тегам