Является ли законным передавать вновь построенный объект ссылкой на функцию?

В частности, является ли следующий законный С++?

class A{};

void foo(A*);
void bar(const A&);

int main(void)
{
    foo(&A());  // 1
    bar(A());  // 2
}

Кажется, что он работает правильно, но это не значит, что он обязательно легален. Это?

Изменить - изменено A& на const A&

Ответы

Ответ 1

1: Учет адреса временного запрещен. Visual С++ позволяет использовать его как расширение языка (по умолчанию расширения языка включены).

2: Это совершенно законно.

Ответ 2

Нет, он против стандарта передает неконстантную ссылку на временный объект. Вы можете использовать ссылку const:

class A{};

void bar(const A&);

int main(void)
{
    bar(A());  // 2
}

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

Ответ 3

foo не допускается в полностью совместимом С++, тогда как в баре все в порядке. Хотя есть шансы, foo будет компилироваться с предупреждением, и бар может или не может компилироваться с предупреждением.

A() создает временный объект, который, если не привязан к ссылке (как в случае бара) или не используется для инициализации именованного объекта, уничтожается в конце полного выражения, в котором он был создан. Временной, созданный для хранения ссылочного инициализатора, сохраняется до конца ссылочного объема. Для случая бар, что вызов функции, так что вы можете использовать внутреннюю панель A совершенно безопасно. Запрещается привязывать временный объект (который является значением r) к неконстантной ссылке. Аналогично запрещается брать адрес rvalue (передать в качестве аргумента для инициализации A для foo).

Ответ 4

Короткий ответ - да.

Если объект получен функцией в качестве параметра ссылки на константу - поскольку вы изменили метод bar(const A&), тогда это полностью законно. Функция может работать на объекте, но объект будет разрушен после вызова функции (адрес временного может быть взят, но не должен быть сохранен и использован после вызова функции - см. Причину ниже).

foo(A*) является законным, так как временный объект уничтожается в конце fullexpression. Однако большая часть компилятора будет выдавать предупреждение о принятии адреса временного.

Исходная версия bar(A&) не должна компилироваться, она соответствует стандарту для инициализации неконстантной ссылки из временного.

Стандартная глава С++ 12.2

3 [...] Временные объекты уничтожаются в качестве последнего шага при оценке fullexpression (1.9), который (лексически) содержит точку, в которой они были созданы. [...]

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

5 Второй контекст - это когда ссылка привязана к временному. Временное, к которому привязана ссылка, или временный объект, являющийся полным объектом для подобъекта, связанного с временной привязкой, сохраняется для срока службы ссылки, за исключением случаев, указанных ниже. Временная привязка к ссылочному элементу в конструкторе ctorinitializer (12.6.2) сохраняется до тех пор, пока конструктор не выйдет. Временная привязка к эталонному параметру в вызове функции (5.2.2) сохраняется до завершения полного выражения, содержащего вызов. Временная привязка к возвращаемому значению в операторе return функции (6.6.3) сохраняется до выхода функции.

A fullexpression - это выражение, которое не является подвыражением другого выражения.

Ответ 5

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

Ответ 6

Это выглядело lke, но это не скомпилировалось с g++ с опцией Wall, вот что я получаю:

[email protected]:~/Desktop$ g++ -Wall a.cpp
a.cpp: In function ‘int main()’:[email protected]:~/Desktop$ g++ -Wall a.cpp
a.cpp: In function ‘int main()’:
a.cpp:8: warning: taking address of temporary
a.cpp:9: error: invalid initialization of non-const reference of type ‘A&’ from a temporary of type ‘A’
a.cpp:4: error: in passing argument 1 of ‘void bar(A&)’
[email protected]:~/Desktop$ 

Похоже, вам нужно будет использовать постоянную ссылку.

Ответ 7

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

int dosomething(error_code& _e = ignore_errorcode()) {
    //do something
}

В приведенном выше случае он построит пустой объект кода ошибки, если не передано error_code функции.

Ответ 8

для//2 вам нужна ссылка const

for//1 Я считаю это законным, но бесполезным

Ответ 9

Совершенно юридически.

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