提问人:user4608393 提问时间:2/26/2015 更新时间:2/26/2015 访问量:284
按值传递的速度要快得多吗?
Is pass by value that much faster?
问:
我听说你应该总是更喜欢C++11中的“按值传递”,因为引入了移动语义。我想看看炒作是怎么回事,并构建了一个测试用例。首先,我的班级:
struct MyClass {
MyClass() { }
MyClass(const MyClass&) { std::cout << "Copy construct" << std::endl; }
MyClass(MyClass&&) { std::cout << "Move construct" << std::endl; }
~MyClass() { }
};
测试线束:
class Test
{
public:
void pass_by_lvalue_ref(const MyClass& myClass)
{
_MyClass.push_back(myClass);
}
void pass_by_rvalue_ref(MyClass&& myClass)
{
_MyClass.push_back(std::move(myClass));
}
void pass_by_value(MyClass myClass)
{
_MyClass.push_back(std::move(myClass));
}
private:
std::vector<MyClass> _MyClass;
};
据推测,应该跑赢大盘(一起,而不是单独)。pass_by_value
pass_by_lvalue_ref
pass_by_rvalue_ref
int main()
{
MyClass myClass;
Test Test;
std::cout << "--lvalue_ref--\n";
Test.pass_by_lvalue_ref(myClass);
std::cout << "--rvalue_ref--\n";
Test.pass_by_rvalue_ref(MyClass{});
std::cout << "--value - lvalue--\n";
Test.pass_by_value(myClass);
std::cout << "--value - rvalue--\n";
Test.pass_by_value(MyClass{});
}
这是我在 GCC 4.9.2 上的输出:-O2
--lvalue_ref--
Copy construct
--rvalue_ref--
Move construct
Copy construct
--value - lvalue--
Copy construct
Move construct
Copy construct
Copy construct
--value - rvalue--
Move construct
如您所见,非函数总共需要 2 个复制构造和 1 个移动构造。该函数总共需要 3 个复制构造和 2 个移动构造。看起来,不出所料,无论如何,对象都会被复制,那么为什么大家都说按值传递呢?pass_by_value
pass_by_value
答:
首先,你的报告是完全有缺陷的。每个函数都推回相同的向量。当该向量的容量用完时(这取决于到目前为止您插入了多少个项目),它将触发重新分配,这将需要更多的移动和/或复制,而不是不触发分配的插入。
二是具有较强的异常安全保障。因此,如果你的移动构造函数不是 noexcept,它就不会使用它(除非该类是不可复制的)。它将改用 copy 构造函数。std::vector::push_back
第三
我听说你应该总是喜欢C++11中的“按值传递” 因为引入了移动语义。
我很确定你没有从任何有信誉的来源听到这个消息。或者实际上不恰当地转述了实际所说的内容。但我没有报价的来源。通常的建议是,如果你无论如何都要在函数中复制你的参数,就不要这样做。只需在参数列表中执行此操作(通过按值传递)。这将允许您的函数将 r 值参数直接移动到其目的地。当你传递 l 值时,它们将被复制,但你还是要这样做。
评论
如果要进行内部复制,则按值传递将比重载对(按右值传递 ref)+(按常量左值 ref 传递)多执行一次移动构造。
如果移动构造很便宜,那么这是少量的运行时开销,以换取更少的编译时间和代码维护开销。
成语是“想要速度吗?无论如何制作副本?按值传递,而不是按常量左值引用传递。
最后,你的基准是有缺陷的,因为你在回推之前没有保留(足够)。重新分配可能会导致额外的操作。哦,让你的移动构造函数 noexcept,因为如果 move 在许多情况下可以抛出,那么符合要求的库会更喜欢副本而不是移动。
评论
push_back
vector
MyClass
noexcept
)_Typename
因为变量的名称是一个非常可怕的命名约定......