显然std::function::operator=(F &&f)是需要的行为完全一样std::function(std::forward<F>(f)).swap(*this);.
除非我遗漏了某些东西,否则这个定义会导致一些多余的移动:
#include <functional>
#include <iostream>
struct A
{
A() {std::cout << "A()\n";}
A(const A &) {std::cout << "A(const A &)\n";}
A(A &&) {std::cout << "A(A &&)\n";}
A &operator=(const A &) {std::cout << "A &operator=(const A &)\n"; return *this;}
A &operator=(A &&) {std::cout << "A &operator=(A &&)\n"; return *this;}
~A() {std::cout << "~A()\n";}
void operator()() const {}
};
int main()
{
std::function<void()> f;
f = A{};
}
Run Code Online (Sandbox Code Playgroud)
打印:
Run Code Online (Sandbox Code Playgroud)A() // Created by `A{}` A(A &&) // Moved into temporary `std::function`, but what's the point? A(A &&) // Moved into `f` ~A() ~A() ~A()
(在GCC 7.2和Clang 3.8上测试)
问题:为什么我们不能通过直接复制/移动(取决于值类别)到LHS存储中来消除一个移动?
编辑:我不是在问为什么移动没有被优化掉,而是为什么它首先被制造出来.
当构造临时的 时std::function,被调用的构造函数是
template< class F >
function( F f );
Run Code Online (Sandbox Code Playgroud)
这是按值传递的,因此第一个移动实际上是移动到此构造函数的参数中,而第二个移动是移动到临时变量中。基本上,典型的实现std::function 存储一个指向其可调用目标的指针,因此交换指针对其swap功能来说就足够了,这不会涉及其可调用目标的任何复制/移动。
由于LHS中存储的可调用目标的类型可能与RHS不同,因此您无法直接执行复制/移动。
swap()参与?这称为复制和交换习惯用法,其行为类似于具有强异常安全性的赋值。
| 归档时间: |
|
| 查看次数: |
159 次 |
| 最近记录: |