最近我一直在分析旧代码的某些部分,在某些情况下,从函数返回的值被分配给 const
变量,有时分配给 const&
。出于好奇,我已经切换到 dissasembly 以查看差异。但在进入正题之前,让我画一个简单的例子来引用一些代码:
struct Data
{
int chunk[1024];
};
Data getData()
{
return Data();
}
int main()
{
const std::string varInit{ "abc" }; // 1
const std::string varVal = "abc"; // 2
const std::string& varRef = "abc"; // 3
const Data dataVal = getData(); // 4
const Data& dataRef = getData(); // 5
return 0;
}
上述代码的以下反汇编是使用禁用优化的 VS2015 获得的。
我不是 asm 专家,但乍一看我会说对于 (1)
和 (2)
执行了类似的操作。尽管如此,令我惊讶的是,与 const&
在变量赋值期间未使用。
当数据按值从函数返回时,可以观察到同样的情况。 (5)
包含与(4)
相关的另外两个操作。
问题很窄:
- 这些额外的操作从何而来,它们的目的是什么?一般不像这里:What's the purpose of the LEA instruction但在目前的情况下。
- 这至少会影响底层数据大小可忽略不计的对象的性能吗? (与示例中使用的
Data
结构对比) - 启用优化后,这会有什么影响吗? (对于发布版本)
顺便说一句,我已经阅读了Why not always assign return values to const reference?关于在分配值时使用 const 和 const& 的优缺点,这可能有些相关但不是问题的一部分。
最佳答案
在情况 (3) 中,编译器在 [ebp-84]
处创建“隐藏”局部变量“std::string”让它命名为_84
并像这样编写代码
const std::string _84 = "abc";
const std::string& varRef = _84;// lea + move (by sense varRef = &_84)
X& v
- 通过意义和二进制代码与 X* v
相同- v
实际上是指向 X
的指针在这两种情况下,只是使用了不同的语法
与情况(5)相同
const Data _20a0 = getData();
const Data& dataRef = _20a0; // by sense dataRef = &_20a0, but by syntax dataRef = _20a0
或者说如果你改为行
const Data& dataRef = getData();
写行
const Data& dataRef = dataVal;
您认为这一行恰好采用了 2 条 asm 指令:
lea eax,[dataVal]
mov [dataRef],eax
代码 (4,5) 和 Data getData()
签名是绝对的噩梦,无话可说
为了更清楚
关于“按值”返回结构 - 函数只能返回寄存器作为结果(al
、ax
、eax
和 rax
在 x64 中)或 2 个寄存器 - edx:eax
(8 字节,高位 edx)或 rdx:rax
(x64 中为 16 字节)
万一
Data getData()
- 不可能返回 Data
原样。怎么?!?
所以实际上你的函数被转换为
Data* getData(Data* p)
{
Data x;
memcpy(p, &x, sizeof(Data));
return p;
}
和代码
//const Data dataVal = getData();
Data _41A0, _3198, dataVal;
memcpy(&_3198, getData(&_41A0), sizeof(Data));
memcpy(&dataVal, &_3198, sizeof(Data));
//const Data& dataRef = getData();
Data _41A0, _3198, _20a0, &dataRef;
memcpy(&_51a8, getData(&_61b0), sizeof(Data));
memcpy(&_20a0, &_51a8, sizeof(Data));
dataRef = &_20a0;// very small influence compare all other
尝试计算编译器有多少无意义的 memcpy?
需要这样写代码
void InitData(Data* p);
Data dataVal;
InitData(&dataVal);
关于c++ - 返回值 const 和 const 赋值——反汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41070592/