为什么 std::函数模板构造函数不使用通用引用?
Why isn't std::function template constructor using universal reference?
我认为具有通用引用参数的构造函数比没有引用的构造函数具有更好的性能。
从 cppreference (https://en.cppreference.com/w/cpp/utility/functional/function/function),我们可以看到std::function
的模板构造函数没有使用引用。
template< class F > function( F f );
是不是搞错了?如果不是,为什么标准不要求构造函数使用通用引用?
编辑:
让我们考虑两种情况。
- F 是内置类型,此处为大小为 4 个字节的函数指针。
使用通用引用:
左值大小写:复制 4 个字节。
右值大小写:复制 4 个字节。(是否会将std::move
应用于内置类型?
按值传递:
所有情况:复制 4 个字节。
- F 是一种具有非平凡复制构造函数的类型,例如按值捕获
std::string
的 lambda 类型。这个例子代表大多数情况,你同意吗?
使用通用引用:
左值大小写:复制构造函数被调用一次
右值大小写:移动构造函数被调用一次
按值传递:
左值案例:移动和复制
右值案例:移动
此分类是否完整?如果是这样,我们可以得出这样的结论:普遍引用并不比按价值传递更差。然后它回到原来的问题。
再次编辑:
也许没有捕获的 lambda 是最常见的情况,其中按值传递实际上不传递任何内容,而按引用传递传递是传递指针。这可能是关键。LWG 2774 与这个问题有关。在评论中看到它。
因为构造函数会移动它的参数,所以接受引用是没有意义的。这归结为关于何时接受价值观的通常建议。
如果你传递一个基元,比如int
,通过引用传递是一种悲观。如果你传递一个复杂类型,比如std::string
,你已经可以把它std::move
到参数中(如果你不这样做,那是因为你无论如何都想要一个副本)。您可以两全其美。
// Bog-standard choice between value and ref; original value only observed
void foo(const int& x) { cout << x << 'n'; }
void foo(const int x) { cout << x << 'n'; } // Better!
void foo(const std::string& x) { cout << x << 'n'; } // Better!
void foo(const std::string x) { cout << x << 'n'; }
// When we want to store
void storeACopy(int);
void foo(const int& x) { storeACopy(x); }
void foo(const int x) { storeACopy(x); } // Better!
void storeACopy(std::string);
void foo(const std::string& x) { storeACopy(x); } // Meh
void foo(std::string x) { storeACopy(std::move(x)); } // Cheap!
// So, best of both worlds:
template <typename T>
void foo(T x) { storeACopy(std::move(x)); }
// This performs a copy when needed, but allows callsite to
// move instead (i.e. total flexibility) *and* doesn't require silly
// refs-to-primitives
它还向调用站点发出信号,除非您明确放弃std::move
所有权,否则不会修改原始对象。
相反,如果函数采用引用,好吧,如果您想屈服,您可能会保存一个移动。但是,搬家应该是超级便宜的,所以我们不担心这一点。如果你不想屈服,那么突然间你必须在调用站点上经历对象副本的僵化。呸!
此模式是充分利用移动语义的关键。
我认为具有通用引用参数的构造函数比没有引用的构造函数具有更好的性能。
你为什么这么认为?你测量过吗?如果我们谈论的是传递int
怎么办?参考(通用/转发与否)并不总是性能提升。
是不是搞错了?
不,这是按值传递函数对象的标准约定。它们旨在复制成本低廉,在实现自己的函数对象时,您应该牢记这一点。
如果不是,为什么标准不要求构造函数使用通用引用?
最终,为什么会这样?:)
- 使用运算符 [] 引用 std::vector 上最后一个元素时出现问题<>
- 引用 std::any 或 not_yet_in_std::whatever 的惯用方式是什么?
- 引用 std::shared:ptr 以避免引用计数
- 将双指针作为参数传递给需要引用 std::vector <double>的函数
- 引用 std::cout 会导致段错误
- 无法通过引用 std::exception 来捕获从 std::exception 派生的类
- 为什么 std::runtime_error 的 c'tor 经常引用 std::string?
- 我可以在循环中引用 std::string 的一部分并将其放在外面吗?
- 引用 std::atomic <bool>的已删除函数错误
- 如何从对象中获取对元组尾部的引用 std::tuple<Head,Tail...>
- 当我编译引用 std::ostream 时,我有一个奇怪的错误弹出
- 错误 C2062:引用 std::map 时键入意外
- 设置 std::function 变量以引用 std::sin 函数
- 指针/引用 std::unordered_set 中的元素
- 迭代器引用 std::vector<std::unique_ptr<T>>
- C++:引用std::map中的计数值;std::multimap是更好的选择吗
- 未定义的引用std::对
- 引用std::basic_string特化string与自定义分配器作为std::string的常量对象,没有开销
- 使用c++,未定义引用std:: Makefile
- 常量引用std::vector