价值与对象

时间:2018-12-24 00:51:50

标签: c++ language-lawyer c++17

[C ++ 17]

当对prvalue表达式求值时,standard说它产生一个值。对于5,该表达式为prvalue,其计算结果为值5

但是,当您具有prvalue时,主要是对象的初始化程序,例如Foo{}。这个表达式的价值是什么?结果将是由prvalue到xvalue转换创建的临时对象吗?这带来了我的更广泛的问题:值和对象之间的区别

3 个答案:

答案 0 :(得分:4)

  

[intro.object]/1

     

在隐式更改联合的活动成员时或在创建临时对象时,将通过定义,通过new表达式创建对象。 一个对象在其构造期间,整个生命周期以及其破坏期间都占据一个存储区域。

无论prvalue是否具有像Foo{}这样的类类型,如文字5都被认为是一个值,然后在确实需要时将该值用于初始化对象,这是当值具体化为对象时。

  

[class.temporary]/2:

     

为了避免创建临时对象,通常会尽可能延迟其实现   不必要的临时对象。

在同一部分下,您会找到一个列表,描述何时实现临时对象。

答案 1 :(得分:2)

是一个抽象概念。值与表征或标识该值的一组实现相关联。例如,价值10美元的人可以买一本书或一顿饭。

一个值可以有多种表示形式。例如,10美元可以用硬币表示,也可以作为位存储在银行帐户中。

对象 ,而银行帐户金额:对象(/银行帐户)代表值(/ 10 $)。 [basic.types]中对此进行了描述:

  

类型T的对象值表示是参与表示类型T的值的位的集合。   对象表示形式中不属于值表示形式的位是填充位。

然后在[intro.object]中指定对象与存储区域相关联:

  

一个对象在其构造期间([class.cdtor]),在其整个生命周期以及其破坏期间([class.cdtor])占据一个存储区域

如果我们考虑的是具有中央处理器单元的抽象机,则该对象与它的值之间的区别更加合理。表示)。当对一个值执行运算时,该值将加载到不同的cpu寄存器中。因此,cpu中的值没有相同的表示形式:与对象内部相同的连续位序列。而且,任何cpu都可以自由地在寄存器中表示值,以最适合其需要。

当cpu执行操作时,它对存储在寄存器中的一条值进行操作。执行完该操作后,CPU可以将结果保存在对象内部的内存中,或继续对该值进行操作。

标准中出现了对值的操作以及对对象的存储或加载中的操作的分解:

  • 一个负载是一个左值到右值的转换[conv.lvalue] 非函数,非数组类型的glvalue T可以转换为prvalue。

  • c ++中的
  • 所有操作将导致一系列具有内置含义的基本操作。 这些操作大多数都适用于值(prvalue),而不适用于对象。在执行这些操作之前,将应用 lvalue-to-rvalue [expr] 每当glvalue表达式作为期望该操作数有prvalue的运算符的操作数出现时,lvalue-to -rvalue,[...]

  • 这些对值进行操作的内置操作的结果始终为prvalue(prvalue只是与任何对象无关的值)。然后,结果值可用作其他内置操作的操作数,或初始化对象(在我们机器内存中的存储操作),{{3 }}: prvalue是一个表达式,其求值初始化一个对象或位字段,或者计算一个运算符的操作数的值,具体取决于其所处的上下文。机器表示,将值存储在对象中的行为是存储。

为了说明这一点,让我们分析一下这段简单的代码:

int main(int argc, char* argv[]){
  int j = 2*argc+1;
  }
  1. 2*argc内置运算符*由两个参数2argc调用。 argc是左值,因此应用了左值到右值argc的值被装入在cpu寄存器中(2可以是一个[basic.lval]),并且执行了multiply 操作
  2. 2*argc的结果是一个prvalue,直接用作第一个操作数(2*argc)+(argc)。然后,此最后一个操作的结果prvalue用于初始化对象j:结果值存储j的内存表示中。

答案 2 :(得分:1)

价值是一个概念;一个物体是一生的东西。对于具有复杂构造函数的类类型,这种区别往往更为重要,但是规则同样适用于所有类型。

考虑以下简单程序:

std::string foo() { return std::string{"Hello"}; }

int main() {
    std::string f = foo();
}

foo不会创建对象。创建对象将涉及到调用类的构造函数以开始对象的生命周期。对于std::string,这可能涉及分配内存和复制字符,并且出于相当明显的原因,我们希望避免执行太多次。

相反,foo返回一个值。它返回“用字符“ Hello”初始化的字符串”的概念。最终,main能够采用该抽象概念并构造一个对象来表示该值。由于这种区别,只创建了一个对象,因此开始和结束对象生存期的额外费用只需支付一次。