最近,我一直在分析旧代码的某些部分,在某些情况下,从函数返回的值已分配给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获取以下代码的反汇编,并禁用了优化。
我不是专家,但乍一看我说
(1)
和(2)
执行类似的操作。尽管如此,我感到惊讶的是(3)
进行了两次额外的操作(lea
和mov
),而之前的版本在变量值赋值期间未使用const&
。
当按值从函数返回数据时,可以观察到相同的情况。 (5)
还有两项与(4)
相关的操作。
问题非常狭窄:
Data
结构形成对比)顺便说一下,我已经阅读Why not always assign return values to const reference?关于使用const和const& amp;的优点和缺点。在分配可能有些相关但不是问题的一部分的值时。
答案 0 :(得分:4)
如果(3)编译器创建隐藏' local var' std :: string'在[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()
签名是绝对的噩梦,没有单词
更清晰
关于返回结构'按价值' - 函数只返回寄存器作为结果(al
,ax
,eax
和rax
在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);