我有以下代码:
std::vector<Info*> filter(int direction)
{
std::vector<Info*> new_buffer;
for(std::vector<Info*>::iterator it=m_Buffer.begin();it<m_Buffer.end();it++)
{
if(((*it)->direction == direction)
{
new_buffer.push_back(*it);
}
}
return new_buffer;
}
std::vector<Info*> &filteredInfo= filter(m_Direction);
有人可以解释这里发生了什么吗? filter方法是否按值返回会创建一个临时的而且filteredInfo永远不会被销毁,因为它是一个引用?
不确定我是否理解正确。在这种情况下,filteredInfo与引用之间的差异是什么?
答案 0 :(得分:6)
您的编译器应该抱怨该代码。
本声明:
<div id="member-info">
<div class="cell-center">Member since June 2015</div>
<div class="cell-right">Θ</div>
</div>
在std::vector<Info*> &filteredInfo= filter(m_Direction);
的位置是个坏主意:
filter
您正在尝试创建对临时对象的引用。即使它与您的编译器成功,也是非法的。
您应该使用:
std::vector<Info*> filter(int direction);
它的效率与你想要的一样。要么std::vector<Info*> filteredInfo= filter(m_Direction);
操作(C ++ 11)会在那里发生,要么Return Value Optimization会启动。对于move
的实现,它应该是优化版本上的RVO(它取决于但是你的编译器质量。
但是,您应该注意到您正在将原始指针复制到向量中,我希望您拥有正确的所有权模型?如果没有,我建议你使用智能指针。
答案 1 :(得分:2)
以下是发生的事情:
std::vector<Info*> new_buffer;
在本地创建一个对象。return new_buffer;
在调用new_buffer
时将filter(m_Direction)
移至临时对象。std::vector<Info*> filteredInfo= filter(m_Direction);
,则临时对象将被移至filteredInfo
,因此没有不必要的副本,而且这是最有效的方式。std::vector<Info*> &filteredInfo= filter(m_Direction);
,那么filteredInfo
被绑定到一个临时对象,这是一个很糟糕的主意,大多数编译器会抱怨这个。答案 2 :(得分:2)
在这里你正确地感到困惑,因为有两个独立的奇怪事实混合在一起:
const
对临时对象的引用,并且对此有一个特殊规则:临时对象不会立即被销毁(就像它会正常发生)但它的生命将延长参考的生活。在代码中:
std::vector<int> foo() {
std::vector<int> x{1,2,3};
return x;
}
int main() {
const std::vector<int>& x = foo(); // legal
for (auto& item : x) {
std::cout << x << std::endl;
}
}
关于将const引用绑定到temporaries这个显然荒谬的规则的原因是在C ++中有一个非常常见的“模式”(1)传递const引用而不是参数值,即使身份是无关紧要的。如果将此(反)模式与隐式转换结合起来,会发生的情况是:例如:
void foo(const std::string& x) { ... }
无法使用
进行调用foo("Hey, you");
没有特殊规则,因为const char *
(文字)被隐式转换为临时std::string
并作为参数绑定到const引用。
(1)从哲学的角度来看,模式确实非常糟糕,因为值是值,引用是引用:这两个是逻辑上不同的概念。 A const reference is not a value and confusing the two can be the source of very subtle bugs。然而,C ++是性能痴迷的,特别是在移动语义之前,传递const引用被认为是传递值的“智能”方式,尽管由于生命周期和别名问题而导致问题,并且使优化器更难以实现。使用现代编译器传递引用应仅用于“大”对象,尤其是那些不即时构建的对象,或者当您真正对对象标识感兴趣而不仅仅是对象价值。