返回值const&和const赋值 - 反汇编

时间:2016-12-09 23:49:57

标签: c++ disassembly

最近,我一直在分析旧代码的某些部分,在某些情况下,从函数返回的值已分配给const变量,有时分配给const&。出于好奇,我已经切换到了解决方案以查看差异。但在谈到这一点之前,让我画一个简单的例子,让我们参考一些代码:

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获取以下代码的反汇编,并禁用了优化。

Disassembly for <code>(1)``(2)``(3)</code> 我不是专家,但乍一看我说(1)(2)执行类似的操作。尽管如此,我感到惊讶的是(3)进行了两次额外的操作(leamov),而之前的版本在变量值赋值期间未使用const&

当按值从函数返回数据时,可以观察到相同的情况。 (5)还有两项与(4)相关的操作。 Disassembly for <code>(4)``(5)</code>

问题非常狭窄:

  • 这些额外的操作来自何处以及它们的目的是什么?不像这里那样一般:What's the purpose of the LEA instruction但在所呈现的背景下。
  • 这是否会影响性能,至少对于底层数据大小可忽略不计的对象? (与示例中使用的Data结构形成对比)
  • 打开优化后会产生任何影响吗? (发布版本)

顺便说一下,我已经阅读Why not always assign return values to const reference?关于使用const和const&amp; amp;的优点和缺点。在分配可能有些相关但不是问题的一部分的值时。

1 个答案:

答案 0 :(得分:4)

如果(3)编译器创建隐藏&#39; local var&#39; std :: string&#39;在[ebp-84],请将其命名为_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()签名是绝对的噩梦,没有单词

更清晰 关于返回结构&#39;按价值&#39; - 函数只返回寄存器作为结果(alaxeaxrax在x64中)或2个寄存器 - edx:eax(8字节,edx in高)或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);