C++中对象初始化与值计算的区别是什么?结合标准条文说明
引自《C++编程语言标准工作草案》[basic.lval/5]:
glvalue的结果是表达式所指代的实体。prvalue的结果是表达式存储到其上下文中的值;类型为cvvoid的prvalue没有结果。结果为值V的prvalue有时被称为持有或命名值V。prvalue的结果对象是由该prvalue初始化的对象;用于计算内置运算符操作数的值的非丢弃prvalue,或类型为cvvoid的prvalue没有结果对象。
[注4:除非prvalue是decltype-specifier的操作数,否则类类型或数组类型的prvalue始终有一个结果对象。对于类型不是cvvoid的丢弃prvalue,会物化一个临时对象,参见[expr.context]。——注结束]
核心区别
二者的核心差异在于执行目标和prvalue的处理逻辑:
- 值计算的目标是得到表达式的结果值,仅关注prvalue持有的值本身,不需要关联到具体的对象存储,完成值提取后prvalue不需要对应结果对象。
- 对象初始化的目标是构造/赋值一个实际存在的对象实体,此时prvalue必须绑定到对应的结果对象,直接将值写入该对象的存储空间,不需要额外产生中间临时对象。
示例说明
1. 值计算场景
int a = 10; int b = a + 20;
上述代码中,a + 20是int类型的prvalue,作为内置加法运算符的操作数参与值计算,只需要提取它持有的结果值30即可,不需要创建对应的结果对象,符合标准中"用于计算内置运算符操作数的值的非丢弃prvalue没有结果对象"的规定。
再举一个值计算的例子:
bool is_greater = 15 > 6;
这里15 > 6的prvalue仅用于值计算得到布尔值true,不需要对应的结果对象,只需要取结果值参与赋值即可。
2. 对象初始化场景
#include <string> std::string s = std::string("hello world");
上述代码中,prvalue std::string("hello world")的结果对象就是左值s,prvalue持有的值直接写入s的存储空间,不会产生中间临时对象,也不需要调用移动/拷贝构造函数,完全符合标准中prvalue的结果对象是被其初始化的对象的规定。
再比如丢弃prvalue的场景:
std::string("temp_test");
按照标准注4的说明,这种丢弃的非void类型prvalue会物化一个临时对象作为该prvalue的结果对象,属于对象初始化范畴,临时对象会在当前语句结束后销毁。
内容的提问来源于stack exchange,提问作者Géry Ogam

