【问题标题】:Aren't elements of a temporary array rvalues themselves?临时数组的元素本身不是右值吗?
【发布时间】:2014-09-08 02:56:19
【问题描述】:
using intArray = int[];
int (&a) [4] = intArray{1, 2, 3, 4};

这是不允许的,因为将非常量左值引用绑定到临时(右值)是非法的。 g++ 4.9.1 和 clang 3.4.2 都返回错误;当aconst 合格时,它编译得很好

int const (&a) [4] = intArray{1, 2, 3, 4};

但是,当我这样做时

int &x = intArray{1, 2, 3, 4} [1];

两个编译器都能正常编译,没有错误。 §5.2.1 Subscripting 说,为此挖掘标准(草案 N3337)

1 后缀表达式后跟方括号中的表达式是后缀表达式。其中一个表达式应具有“指向 T 的指针”类型,而另一个应具有无作用域枚举或整数类型。 结果是“T”类型的左值。“T”类型应该是完全定义的对象类型。表达式 E1[E2] 与 *((E1)+(E2)) 相同(根据定义)

2 花括号初始化列表不能与内置下标运算符一起使用。

  1. 如果我选择 1 那么我不明白为什么标准允许构造临时数组,因为在其中下标一个元素会给出一个左值,即我可以从一个临时数组中获取一个左值这与临时对象的原始概念相矛盾,只能绑定到 const 左值引用或右值引用。

  2. 如果我使用 2 那么为什么编译器在我执行 {1, 2, 3, 4}[1] 时不会抛出错误?

【问题讨论】:

    标签: c++ arrays c++11 temporary rvalue


    【解决方案1】:

    问题 1

    关于不将临时变量绑定到左值的规则并不能提供绝对的安全性。它可以防止部分此类错误,但不是全部。我怀疑为了防止所有此类错误,需要将“临时性”的概念纳入类型系统,就像const 一样。然后,在您知道您不会将参考保留时间超过临时生命周期的情况下,您可以“抛弃临时性”。委员会认为我们拥有的规则是值得的,大概他们也认为继续努力是不值得的。

    再举一个例子,vector<int>(4)[0] 也返回一个左值,即使 operator[] 调用是在临时上进行的。因此,该标准不会禁止构建临时向量,我也不认为它应该禁止临时数组。好的,所以vector 是用户定义的类型,而数组是内置的,但除此之外,我认为情况相似。

    如果你完全使用数组,尤其是临时数组,那么在某种程度上,标准认为你得到了你应得的。它不会仅仅因为可以从一个中获取一个左值就禁止临时数组。

    不过,我认为你有一个有效的一般观点。可能可以在数组右值上更安全地定义下标,因为编译器有必要的信息。它可以评估为一个右值,其值是相应数组元素的值。这可能会令人困惑或不方便,因为它与通常的下标表达式不一致,但它会更安全:-) 如果你写struct A {int a;},那么A().a 是一个右值,所以我认为它不会完全不可能将该原则应用于数组。当然,这将是一个重大变化。

    问题 2

    您没有在花括号初始化列表上使用下标。您在临时使用它,而该临时对象恰好是使用新型初始值设定项语法构造的。也就是说,你的表达式解析的是(intArray{1, 2, 3, 4})[1],而不是intArray({1, 2, 3, 4}[1])

    【讨论】:

    • 但是由于整个数组是临时的并且可能很快就会死掉,所以对该元素的引用不会悬空吗?
    • @legends2k:是的,它会的。您的问题似乎包含一个假设,即该标准旨在防止此类事情在格式良好的代码中发生,但该标准没有。它只有一个规则可以捕获一大类与该结果有关的错误。或者我想有两条规则:(1)不能将临时绑定到非常量引用和(2)使用临时初始化程序声明 const 引用可以延长临时的寿命。
    • 您的问题似乎包含一个假设,即该标准旨在防止此类事情在格式正确的代码中发生,但该标准没有。是的,我认为这是一个俯瞰。如果可能的话,您能否指出标准表现出此类宽大处理的其他实例?
    猜你喜欢
    • 2010-11-12
    • 2011-01-09
    • 2014-07-23
    • 1970-01-01
    • 2012-04-11
    • 1970-01-01
    • 1970-01-01
    • 2020-11-30
    • 2013-07-04
    相关资源
    最近更新 更多