以下代码如何在C ++中运行?这是合乎逻辑的吗?
const int &ref = 9;
const int &another_ref = ref + 6;
为什么C ++允许对const引用进行文字初始化,而非const引用不允许这样做? E.g:
const int days_of_week = 7;
int &dof = days_of_week; //error: non const reference to a const object
这可以通过以下事实来解释:非const引用可用于更改它所引用的变量的值。因此,C ++不允许对const变量进行非const引用。
这可能是一个可能的解释吗? C ++不允许:
int &ref = 7;
因为这不符合逻辑,但是:
const int &ref = 7;
几乎相当于:
const int val = 7;
因此const变量允许进行文字初始化。
P.S。:我目前正在研究Lippman的C ++入门。
答案 0 :(得分:11)
可以使用文字和临时值初始化常量引用,因为您可以将它们简单地转换为显式变量:
int const& ans = 42;
// tranformed:
int __internal_unique_name = 42;
int const& ans = __internal_unique_name;
或者延长寿命时,例如函数参数:
f("foobar");
// transformed:
{
string __internal_unique_name = "foobar";
f(__internal_unique_name);
}
(注意这种情况下的显式块。)
虽然在非常数情况下可以做类似的事情,但在当前的C ++中是不允许的。但是,C ++ 0x(下一个标准)将具有r值引用。
如果不清楚,代码中的ref + 6
会创建一个临时对象,您可以将其视为:
int const& ref = int(9);
int const& another_ref = int(ref + 6);
// transformed:
int __A = 9;
int const& ref = __A;
int __B = ref + 6;
int const& another_ref = __B;
这可以帮助您理解/可视化正在发生的事情,但您不应该编写这样的真实代码。此外,我使用双下划线名称来说明这些名称是实现细节(由编译器使用),不应该被您使用。包含相邻下划线的任何名称都保留给C ++实现。
答案 1 :(得分:9)
所以你可以写这样的代码:
void f( const string & s ) {
}
f( "foobar" );
虽然严格来说这里实际发生的事情并不是文字绑定到const引用 - 而是创建了一个temprary字符串对象:
string( "foobar" );
并且此无名字符串绑定到引用。
请注意,创建非参数引用变量实际上是非常不寻常的 - 引用的主要目的是作为函数参数和返回值。
答案 2 :(得分:2)
您的代码归结为C ++标准规则,其中临时值的生命周期绑定到分配给它的const
引用的生命周期。有关其他详细信息,请参阅GoTW文章GotW #88: A Candidate For the “Most Important const”。
例如,Alexandrescu和Marginean在Dr. Dobbs文章“Generic: Change the Way You Write Exception-Safe Code — Forever”中描述的ScopeGuard
实现取决于此行为。