我正在审查一个同事的代码,我发现他在全球范围内定义了几个常量:
const string& SomeConstant = "This is some constant text";
就个人而言,这对我来说闻起来很糟糕,因为引用是指我假设的是从给定的char数组构造的“匿名”对象。
从句法上讲,它是合法的(至少在VC ++ 7中),它似乎运行,但实际上我宁愿让他删除&因此,对于它正在做什么没有任何含糊之处。
那么,这真的很安全合法吗?我很着迷?构造的临时对象是否具有保证的寿命?我一直认为以这种方式使用的匿名对象在使用后被破坏了......
所以我的问题也可以推广到匿名对象的生命周期。标准是否规定了匿名对象的生命周期?它是否与同一范围内的任何其他对象具有相同的生命周期?或者仅仅给出表达式的生命周期?
此外,当它作为本地时,它显然有不同的范围:
class A
{
string _str;
public:
A(const string& str) :
_str(str)
{
cout << "Constructing A(" << _str << ")" << endl;
}
~A()
{
cout << "Destructing A(" << _str << ")" << endl;
}
};
void TestFun()
{
A("Outer");
cout << "Hi" << endl;
}
节目:
构建A(外部); 破坏A(外); 喜
答案 0 :(得分:14)
这完全合法。在程序结束之前不会被破坏。
编辑:是,保证:
“所有没有动态的对象 存储持续时间,没有线程 存储持续时间,并非本地 有静态存储时间。该 这些物品的存放应该持续 在该计划的持续时间 (3.6.2,3.6.3)。“
- 2008 Working Draft, Standard for Programming Language C++,§3.7.1p。 63
正如马丁所说,这不是完整的答案。标准草案进一步注释(§12.2,第250-1页):
“创建了类型的临时工具 在各种情况下:绑定一个右值 参考(8.5.3)[...]即使 临时对象的创建 避免了(12.8),所有的语义 限制应该像是一样受到尊重 临时对象已创建。 [...]临时物品被摧毁 作为评估的最后一步 完全表达(1.9)(词汇) 包含他们所处的位置 创建。 [...]有两种情况 其中临时的人被摧毁了 一个不同于结尾的点 充分表达。 [...] 第二 context是绑定引用的时间 暂时的。临时到哪 引用是绑定还是 临时的,这是完整的对象 参考的子对象 坚持一生 除非另有说明,否则参考 下方。“
我用g ++测试过,如果这让你感觉更好。 ;)
答案 1 :(得分:11)
是的,它是有效且合法的。
const string& SomeConstant = "This is some constant text";
// Is equivalent too:
const string& SomeConstant = std::string("This is some constant text");
因此,您正在创建一个临时对象 这个临时对象绑定到const&amp;因此它的生命周期延长到它所绑定的变量的寿命(即比它创建的表达式更长)。
标准保证这一点。
虽然这是合法的。我不会用它。最简单的解决方案是将其转换为const std :: string。
在这种情况下,因为变量在全局范围内,所以它对程序的全长有效。因此,只要执行进入main(),就可以使用它,并且在执行退出main()之后不应该访问它。
虽然在此之前技术上可能是可用的,但是在全局对象的构造函数/析构函数中对它的使用应该用已知的全局变量初始化顺序问题进行调整。
另一方面,这不会遇到问题:
char const* SomeConstant = "This is some constant text";
可以在任何时候使用。只是一个想法。
答案 2 :(得分:6)
这可能是合法的,但仍然很难看。省略参考!
const string SomeConstant = "This is some constant text";
答案 3 :(得分:4)
这是合法的,因为它很难看。
答案 4 :(得分:2)
使用const
引用扩展一个临时变量是合法的,这由Alexandrescu的ScopeGaurd使用,请参阅Herb Sutter称为A candidate for the "Most important const
"的这个优秀解释。
据说这个具体案例是滥用C ++的这个特性,应该删除引用,留下一个简单的const string
。
答案 5 :(得分:0)
通过将其声明为const(这意味着它无法更改)然后将其作为引用,这意味着有人可能会改变它,至少看起来像是糟糕的形式。另外,正如我相信你明白的那样,全局变量很糟糕,很少需要。
答案 6 :(得分:0)
好吧,如果我不在深处,大家会纠正我,但是我的结论是听取你所有出色的回答:
A)它在语法和逻辑上是合法的,&amp;将temp / anonymous的生命周期从表达级别扩展到引用的生命周期。我在VC ++ 7中使用以下命令验证了这一点:
class A {
public: A() { cout << "constructing A" << endl; }
public: ~A() { cout << "destructing A" << endl; }
};
void Foo()
{
A();
cout << "Foo" << endl;
}
void Bar()
{
const A& someA = A();
cout << "Bar" << endl;
}
int main()
{
Foo(); // outputs constructing A, destructing A, Foo
Bar(); // outputs constructing A, Bar, destructing A
return 0;
}
B)虽然它是合法的,但它可能导致对实际生命周期的一些混淆,并且在这些情况下的参考不会给你任何声明它作为非参考的好处,因此可能应该避免参考,甚至可能是额外的空间。由于它没有任何好处,因此不必进行混淆。
感谢所有答案,这是一个非常有趣的讨论。所以它的长短不一:是的,它在语法上是合法的,不会因为生命周期延长而在技术上没有危险,但它没有增加任何东西,可能会增加成本和混乱,所以为什么要这么麻烦。
听起来不错?