Ответ 1
1: Учет адреса временного запрещен. Visual С++ позволяет использовать его как расширение языка (по умолчанию расширения языка включены).
2: Это совершенно законно.
В частности, является ли следующий законный С++?
class A{}; void foo(A*); void bar(const A&); int main(void) { foo(&A()); // 1 bar(A()); // 2 }
Кажется, что он работает правильно, но это не значит, что он обязательно легален. Это?
Изменить - изменено A&
на const A&
1: Учет адреса временного запрещен. Visual С++ позволяет использовать его как расширение языка (по умолчанию расширения языка включены).
2: Это совершенно законно.
Нет, он против стандарта передает неконстантную ссылку на временный объект. Вы можете использовать ссылку const:
class A{};
void bar(const A&);
int main(void)
{
bar(A()); // 2
}
Таким образом, хотя некоторые компиляторы согласятся с этим, и он будет работать до тех пор, пока не будет использовать память после точки с запятой, соответствующий компилятор ее не примет.
foo не допускается в полностью совместимом С++, тогда как в баре все в порядке. Хотя есть шансы, foo будет компилироваться с предупреждением, и бар может или не может компилироваться с предупреждением.
A() создает временный объект, который, если не привязан к ссылке (как в случае бара) или не используется для инициализации именованного объекта, уничтожается в конце полного выражения, в котором он был создан. Временной, созданный для хранения ссылочного инициализатора, сохраняется до конца ссылочного объема. Для случая бар, что вызов функции, так что вы можете использовать внутреннюю панель A совершенно безопасно. Запрещается привязывать временный объект (который является значением r) к неконстантной ссылке. Аналогично запрещается брать адрес rvalue (передать в качестве аргумента для инициализации A для foo).
Короткий ответ - да.
Если объект получен функцией в качестве параметра ссылки на константу - поскольку вы изменили метод 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 - это выражение, которое не является подвыражением другого выражения.
Те объекты A будут существовать только до тех пор, пока выполнение не достигнет точки с запятой. Таким образом, вызовы безопасны, но не пытайтесь сохранить указатель и использовать его позже. Кроме того, компилятор может потребовать, чтобы строка bar ссылалась на константу.
Это выглядело 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$
Похоже, вам нужно будет использовать постоянную ссылку.
Это законно. Мы иногда используем его, чтобы предоставить значение по умолчанию, которое мы можем игнорировать.
int dosomething(error_code& _e = ignore_errorcode()) {
//do something
}
В приведенном выше случае он построит пустой объект кода ошибки, если не передано error_code
функции.
для//2 вам нужна ссылка const
for//1 Я считаю это законным, но бесполезным
Совершенно юридически.
Объект будет существовать в стеке во время вызова функции, как и любая другая локальная переменная.