11

我正在查看一位同事的代码,我看到他在全局范围内定义了几个常量:

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(外);你好

4

7 回答 7

14

这是完全合法的。在程序结束之前它不会被破坏。

编辑:的,可以保证:

“所有没有动态存储持续时间、没有线程存储持续时间和非本地对象都有静态存储持续时间。这些对象的存储应持续到程序的持续时间(3.6.2、3.6.3)。 "

-- 2008 工作草案,C++ 编程语言标准,第 3.7.1 页。63

正如马丁所指出的,这不是全部答案。标准草案进一步说明(§ 12.2, p. 250-1):

“类类型的临时对象是在各种上下文中创建的:将右值绑定到引用 (8.5.3) [...] 即使避免创建临时对象 (12.8),所有语义限制都应得到尊重,就好像临时对象已被创建。[...] 临时对象被销毁作为评估完整表达式 (1.9) 的最后一步,该完整表达式 (1.9) 包含创建它们的点。 [...] 有两种上下文其中临时对象在与完整表达式末尾不同的点被销毁。[...]第二个上下文是引用绑定到临时对象时。引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在,除非下面指定。”

如果这让你感觉更好,我在 g++ 中进行了测试。;)

于 2009-06-22T17:37:43.773 回答
11

是的,它是有效且合法的。

const string& SomeConstant = "This is some constant text";

// Is equivalent too:

const string& SomeConstant = std::string("This is some constant text");

因此,您正在创建一个临时对象。
这个临时对象绑定到一个 const&,因此它的生命周期也延长到它所绑定的变量的生命周期(即比创建它的表达式长)。

这是由标准保证的。

笔记:

虽然是合法的。我不会使用它。最简单的解决方案是将其转换为 const std::string。

用法:

在这种情况下,因为变量在全局范围内,所以它在程序的整个长度内都有效。所以只要执行进入main()就可以使用它,并且在exectiuon退出main()之后不应该访问它。

尽管在此之前它在技术上可能是可用的,但您在全局对象的构造函数/析构函数中的使用应该与全局变量初始化顺序的已知问题相缓和。

额外的想法:

另一方面,这不会受到问题的影响:

char const* SomeConstant = "This is some constant text";

并且可以在任何时候使用。只是一个想法。

于 2009-06-22T18:38:33.163 回答
6

这可能是合法的,但仍然很丑陋。省略参考!

const string SomeConstant = "This is some constant text";
于 2009-06-22T17:52:32.787 回答
4

它既丑陋又合法。

于 2009-06-22T18:36:23.010 回答
2

使用引用扩展临时变量是合法的const,Alexandrescu 的ScopeGaurd使用了这个变量,参见 Herb Sutter 的出色解释,称为“最重要的候选者const

话虽如此,这种特定情况是对 C++ 的这一特性的滥用,应该删除引用,留下一个普通的const string.

于 2009-06-22T18:35:18.410 回答
0

通过将其声明为 const (这意味着它无法更改)然后将其设为引用,这意味着有人可能会更改它,至少看起来是一种不好的形式。另外,我相信你明白,全局变量是不好的,而且很少需要。

于 2009-06-22T19:06:47.767 回答
0

好的,如果我离题了,人们会纠正我,但我的结论是听完你所有的出色回答:

A)它在句法和逻辑上都是合法的, & 将临时/匿名的生命周期从表达式级别之外扩展到引用的生命周期。我在 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)虽然它是合法的,但它可能会导致对实际生命周期的一些混淆,并且在这些情况下,引用不会给您将其声明为非引用的任何好处,因此应该避免引用,甚至可能是额外的空间. 由于它没有任何好处,因此这是不必要的混淆。

感谢所有的答案,这是一个非常有趣的讨论。所以它的长短:是的,它在语法上是合法的,不,随着生命周期的延长,它在技术上并不危险,但它不会增加任何东西,并且可能会增加成本和混乱,所以为什么要打扰。

听起来对吗?

于 2009-06-23T15:15:45.450 回答