全局常量字符串& 我闻起来很臭,真的安全吗?

发布于 2024-07-24 12:00:04 字数 888 浏览 4 评论 0原文

他在全局范围内定义了几个常量:

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

我正在审查一位同事的代码,我发现 字符数组。

从语法上讲,它是合法的(至少在 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(外层); 你好

I'm reviewing a collegue's code, and I see he has several constants defined in the global scope as:

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

Personally, this smells bad to me because the reference is referring to what I'm assuming is an "anonymous" object constructed from the given char array.

Syntactically, it's legal (at least in VC++ 7), and it seems to run, but really I'd rather have him remove the & so there's no ambiguity as to what it's doing.

So, is this TRULY safe and legal and I'm obsessing? Does the temp object being constructed have a guaranteed lifetime? I had always assumed anonymous objects used in this manner were destructed after use...


So my question could also be generalized to anonymous object lifetime. Does the standard dictate the lifetime of an anonymous object? Would it have the same lifetime as any other object in that same scope? Or is it only given the lifetime of the expression?


Also, when doing it as a local, it's obviously scoped differently:

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;
}

Shows:

Constructing A(Outer);
Destructing A(Outer);
Hi

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

残龙傲雪 2024-07-31 12:00:04

这是完全合法的。 直到程序结束它才会被破坏。

编辑:,保证:

“所有没有动态的对象
存储时间,无线程
存储持续时间,并且不是本地的
具有静态存储时间。 这
这些对象的存储应持续
在计划期间
(3.6.2、3.6.3)。”

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

正如 Martin 指出的那样,这并不是完整的答案。标准草案进一步指出(第 12.2 页,第 250-1 页):

“创建了类类型的临时对象
在各种上下文中:绑定右值
参考文献 (8.5.3) [...] 即使
临时对象的创建
被避免(12.8),所有语义
应尊重限制,如同
临时对象已创建。
[...] 临时对象被销毁
作为评估的最后一步
完整表达式 (1.9) that(词汇上)
包含他们所在的点
创建的。 [...]有两种情况
其中临时对象被销毁于
与结尾不同的点
充分表达。 [...] 第二
上下文是当引用被绑定时
到一个临时的。 临时到哪个
参考已绑定或
临时的即完整的对象
引用的子对象的
是绑定持续存在的一生
除非另有说明,否则参考
下面。”

我在 g++ 中进行了测试,这是否会让您感觉好一些。;)

It's completely legal. It will not be destructed until the program ends.

EDIT: Yes, it's guaranteed:

"All objects which do not have dynamic
storage duration, do not have thread
storage duration, and are not local
have static storage duration. The
storage for these objects shall last
for the duration of the program
(3.6.2, 3.6.3)."

-- 2008 Working Draft, Standard for Programming Language C++, § 3.7.1 p. 63

As Martin noted, this is not the whole answer. The standard draft further notes (§ 12.2, p. 250-1):

"Temporaries of class type are created
in various contexts: binding an rvalue
to a reference (8.5.3) [...] Even when
the creation of the temporary object
is avoided (12.8), all the semantic
restrictions shall be respected as if
the temporary object had been created.
[...] Temporary objects are destroyed
as the last step in evaluating the
full-expression (1.9) that (lexically)
contains the point where they were
created. [...] There are two contexts
in which temporaries are destroyed at
a different point than the end of the
full-expression. [...] 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
of a subobject to which the reference
is bound persists for the lifetime of
the reference except as specified
below."

I tested in g++ if that makes you feel any better. ;)

野侃 2024-07-31 12:00:04

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

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() 就可以使用它,并且在执行退出 main() 后不应该访问它。

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

额外的想法:

另一方面,这不会遇到问题:

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

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

Yes it is valid and legal.

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

// Is equivalent too:

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

Thus you are creating a temporary object.
This temporary object is bound to a const& and thus has its lifetime extended to the lifespan of the variable it is bound too (ie longer than the expression in which it was created).

This is guranteed by the standard.

Note:

Though it is legal. I would not use it. The easist solution would be to convert it into a const std::string.

Usage:

In this situation because the variable is in global scope it is valid for the full length of the program. So it can be used as soon as execution enters main() and should not be accessed after executiuon exits main().

Though it technically may be avilable before this your usage of it in constructors/destructors of global objects should be tempered with the known problem of global variable initialization order.

Extra Thoughts:

This on the other hand will not suffer from the problem:

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

And can be used at any point. Just a thought.

送君千里 2024-07-31 12:00:04

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

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

It might be legal, but still ugly. Leave out the reference !

const string SomeConstant = "This is some constant text";
芸娘子的小脾气 2024-07-31 12:00:04

它既合法又丑陋。

It's as legal as it's ugly.

瞳孔里扚悲伤 2024-07-31 12:00:04

使用 const 引用扩展临时变量是合法的,这是 Alexandrescu 的 使用的ScopeGaurd 看到了 Herb Sutter 的精彩解释,称为 “最重要的 const 的候选者”

话虽这么说,这个特定案例滥用了 C++ 的这一功能,应该删除引用,留下一个简单的 const string

It's legal to extend a temporary variable with a const reference, this is used by Alexandrescu's ScopeGaurd see this excellent explanation by Herb Sutter called A candidate for the "Most important const".

That being said this specific case is an abuse of this feature of C++ and the reference should be removed leaving a plain const string.

幼儿园老大 2024-07-31 12:00:04

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

By declaring it as const (which means it can't be changed) and then making it a reference, which implies that someone might change it, seems like bad form, at the very least. Plus, as I am sure you understand, global variables are BAD, and rarely necessary.

折戟 2024-07-31 12:00:04

好吧,如果我说得离题了,请大家纠正我,但这是我听了你们所有精彩回答后得出的结论:

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) 虽然它是合法的,但它可能会导致对实际生命周期的一些混乱,并且在这些情况下的引用不会给你声明它为非引用的任何好处,因此引用也许应该避免,甚至可能是额外的空间。 既然没有任何好处,那就是不必要的混淆。

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

听起来对吗?

Okay, folks correct me if I'm off the deep end, but here's my conclusions listening to all of your excellent responses:

A) it is syntactically and logically legal, the & extends the lifetime of the temp/anonymous from beyond expression level to the life of the reference. I verified this in VC++7 with:

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) Though it is legal, it can lead to some confusion as to the actual lifetime and the reference in these cases give you no benefit of declaring it as a non-reference, thus the reference should probably be avoided and may even be extra space. Since there's no benefit to it, it's unnecessary obfuscation.

Thanks for all the answers it was a very interesting dicussion. So the long and short of it: Yes, it's syntactically legal, no it's not technically dangerous as the lifetime is extended, but it adds nothing and may add cost and confusion, so why bother.

Sound right?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文