agh*_*ast 10 c++ pass-by-value stl-algorithm c++17
我正在查看std::find_ifcppreference.com上的各种签名,我注意到采用谓词函数的风格似乎是按值接受它:
template< class InputIt, class UnaryPredicate >
InputIt find_if( InputIt first, InputIt last,
UnaryPredicate p );
Run Code Online (Sandbox Code Playgroud)
如果我正确理解它们,带有捕获变量的lambdas会为其数据的引用或副本分配存储空间,因此可能会出现"按值传递"意味着会为调用复制捕获数据的副本.
另一方面,对于函数指针和其他直接可寻址的东西,如果直接传递函数指针,而不是通过引用指针(指向指针),性能应该更好.
首先,这是正确的吗?UnaryPredicate以上是否是一个按值参数?
第二,我对传递lambdas的理解是否正确?
第三,在这种情况下,是否有理由通过价值而非参照?更重要的是,是不是有一些足够模糊的语法(hello,通用引用)可以让编译器做任何想要获得最大性能的东西?
Sto*_*ica 12
上面的UnaryPredicate是否是一个按值参数?
是的,这就是它在函数参数列表中所说的内容.它接受推导的值类型.
除此之外,lambda表达式是prvalues.这意味着,使用c ++ 17保证的复制省略,直接从lambda表达式p初始化.在将函数传递给函数时,没有额外的闭包副本或捕获的对象(函数可能会在内部制作更多副本,但这并不常见).
如果谓词是通过引用传递的,则需要实现临时对象.因此对于lambda表达式,交换机无法通过引用获取任何内容.
如果你有其他类型的谓词,这些谓词可以扩展,那么你可以传入std::reference_wrapper那个谓词对象,以获得廉价的"句柄".包装器operator()将做正确的事情.
这个定义大多是历史性的,但是现在通过价值传递来实现它并不是一个问题.
为了详细阐述为什么引用语义会很糟糕,让我们试着用它来度过这些年.一个简单的左值引用不会,因为现在我们不支持绑定到右值.const左值引用也不会这样做,因为现在我们要求谓词不修改任何内部状态,为什么?
所以直到c ++ 11,我们真的没有其他选择.传递值优于参考值.有了新标准,我们可能会修改我们的方法.为了支持rvalues,我们可以添加一个rvalue引用重载.但这是一种冗余练习,因为它不需要做任何不同的事情.
通过传递一个值,调用者可以选择如何创建它,对于prvalues,在c ++ 17中,它实际上是免费的.如果调用者需要,他们可以明确地提供引用语义.所以没有任何东西丢失,我认为在简单的使用和API设计方面获得了很多.
其实有多种原因:
您总是可以将推导的值参数转换为使用引用语义,但std::ref(x)反之则不行:只需传递而不是x. std::reference_wrapper<T>并不完全等同于传递引用,但特别是对于函数对象,它做正确的事情。也就是说,按值传递泛型参数是更通用的方法。
通过引用传递 ( T&) 不适用于临时或const对象,T const&不适用于 non- const&,即,唯一的选择是T&&(forwarding reference) 在 C++11 之前不存在并且算法接口不存在'自 C++98 引入以来,t 发生了变化。
与任何类型的引用参数不同,值参数可以被复制省略,包括转发引用。