In Visual C++ 2013, it is legal to assign a temporary value to a const reference, for example
const int& a = 1;
In a large software project, I now stumbled upon a single line of code that took around 10 ms to execute:
const std::vector<Item>& desc = (hasItems) ? instance->getItems() : std::vector<Item>();
Item is a struct with around 20 bytes, instance->getItems() returns a const std::vector< Item>&. I did not see any reason why this line should take longer than an instant to execute, so I played around a bit and found out that
const std::vector<Item>& desc = std::vector<Item>();
also takes 10 ms, while
std::vector<Item> items;
const std::vector<Item>& desc = items;
is near-instant, i.e. 0.00.. ms, as you would expect.
The thing is, I can reliably reproduce this issue in the existing, complex software project, but in any condensed minimal example, both versions run equally fast. I have tested all of this in a release build with optimizations enabled. Is there any chance that one of these optimization makes this exception to assign a value to a const reference really slow? I would really like to know what causes this behavior. Does anyone have a clue what causes this?
Following up, is there a warning for assigning a value to a const reference that I accidentally disabled? If so, what is its id? It would be handy if the compiler could point out other places in the code where this happens.
Edit: The timings were done with a simple CPU clock right before and right after the code of interest, divided by the clock cycles per second. It's not too accurate, but gives you a general idea of the difference between 10.something and 0.something. And it's not fluctuating in any way, it is perfectly reproducible in this specific example. There is a significant difference in execution time.
答案 0 :(得分:2)
const std::vector<Item>& desc = (hasItems) ? instance->getItems() : std::vector<Item>();
你可能没想到,但这一行会复制getItems
的返回值所引用的向量。
正式地,由条件运算符执行的类型强制规则共同实现了这一点。实际上,编译器别无选择:当引用绑定到临时引用时,编译器需要生成代码以在引用最终超出范围时销毁该临时代码 - 但如果相同的引用可以绑定到那么这将变得棘手有时是临时的,有时是左右的。正是为了避免这种情况,编写类型强制规则以确保在您的情况下在条件的两个分支上创建临时。
这样的事情应该会有所帮助:
std::vector<Item> blank;
const std::vector<Item>& desc =
(hasItems) ? instance->getItems() : blank;
或者,我想,你可以设计getItems()
以在没有项目的情况下返回对有效空向量的引用,并且不需要调用者跳过箍。为此目的保留一个静态的常常为空的向量变量并非不合理。