Return 值 const 和 const 赋值 - 反汇编

Return value const& and const assignment - dissassembly

最近我一直在分析旧代码的某些部分,在某些情况下,从函数返回的值被分配给 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) 执行了类似的操作。尽管如此,令我惊讶的是 (3) 与以前的版本相比,在变量值分配期间未使用 const& 进行了两个额外的操作(leamov)。

当数据按值从函数返回时,可以观察到同样的情况。 (5)(4) 多了两个操作。

问题很窄:

顺便说一下,我已经阅读了 关于在分配值时使用 const 和 const& 的优缺点,这些值可能有些相关但不是问题的一部分。

如果 (3) 编译器在 [ebp-84] 处创建 'hidden' 本地变量 '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()签名绝对是噩梦,无语


为了更清楚 关于 return 结构 'by value' - 函数只能 return 注册为结果(alaxeaxrax in x64 ) 或 2 个寄存器 - edx:eax(8 字节,高位 edx)或 rdx:rax(x64 中的 16 字节)

万一 Data getData() - 不可能 return 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);