具体来说,以下是合法的C ++吗?
1 2 3 4 5 6 7 8 9 10
| class A{};
void foo(A*);
void bar(const A&);
int main(void)
{
foo(&A()); // 1
bar(A()); // 2
} |
它似乎可以正常工作,但这并不意味着它一定合法。 是吗?
编辑-将A&更改为const A&
1:不允许使用临时地址。 Visual C ++允许它作为语言扩展(默认情况下,语言扩展处于启用状态)。
2:这是完全合法的。
不,将非常量引用传递给临时对象是违反标准的。您可以使用const引用:
1 2 3 4 5 6 7 8
| class A{};
void bar(const A&);
int main(void)
{
bar(A()); // 2
} |
因此,尽管有些编译器会接受它,并且只要不使用分号后的内存,它就可以工作,而合规的编译器将不会接受它。
在完全符合标准的C ++中不允许foo,而bar可以。尽管有机会,但foo会带有警告编译,而bar也可能会或可能不会带有警告编译。
A()创建一个临时对象,除非绑定到引用(如bar所示)或用于初始化命名对象,否则它将在创建该对象的完整表达式的末尾销毁。为保存参考初始化程序而创建的临时目录将一直保留到其参考范围的末尾。对于bar来说,这就是函数调用,因此您可以完美安全地使用A内部bar。禁止将临时对象(是右值)绑定到非常量引用。同样,也禁止使用右值的地址(作为参数传递以初始化foo的A)。
简短的回答是。
如果通过函数将对象作为const引用参数接收-如已修改bar(const A&)方法,则完全合法。该函数可以在该对象上操作,但是在函数调用之后该对象将被销毁(可以使用临时地址,但在函数调用之后不得存储和使用该地址-请参见下文的原因)。
foo(A*)也是合法的,因为临时对象在全表达式结束时被销毁。但是,大多数编译器都会发出有关获取临时地址的警告。
bar(A&)的原始版本不得编译,这是从临时初始化非常量引用的标准。
C++ standard chapter 12.2
3 [...] Temporary objects are destroyed as the last step in evaluating the fullexpression (1.9) that (lexically) contains the point where they were created. [...]
4 There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when an expression appears as an initializer for a declarator defining an object. In that context, the temporary that holds the result of the expression shall persist until the object’s initialization is complete. [...]
5 The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference except as specified below. A temporary bound to a reference member in a constructor’s ctorinitializer (12.6.2) persists until the constructor exits. A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full expression containing the call.
A temporary bound to the returned value in a function return statement (6.6.3) persists until the function exits.
全表达式是不是另一个表达式的子表达式的表达式。
那些A对象将仅存在,直到执行到达分号为止。因此,调用是安全的,但不要尝试保存指针并在以后使用它。另外,编译器可能要求bar接受const引用。
看起来它可能会起作用,但是它没有使用带有Wall选项的g ++进行编译,这是我得到的:
1 2 3 4 5 6 7
| michael@hardy-lenovo:~/Desktop$ g++ -Wall a.cpp
a.cpp: In function ‘int main()’:michael@hardy-lenovo:~/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&)’
michael@hardy-lenovo:~/Desktop$ |
看起来您将需要使用常量引用。
对于// 2,您需要一个const引用
对于/ / 1我认为这是合法的,但没用
是合法的我们有时会使用它来提供一个我们可能要忽略的默认值。
1 2 3
| int dosomething(error_code& _e = ignore_errorcode()) {
//do something
} |
在上述情况下,如果没有error_code传递给函数,它将构造一个空的错误代码对象。
完全合法。
该对象将在函数调用期间存在于堆栈中,就像其他任何局部变量一样。