【发布时间】:2021-08-24 16:39:50
【问题描述】:
我一直试图了解 std::bind 的工作原理。因此,使用不同的示例进行工作。以下是我无法理解其输出的示例程序。
版本 1
class NAME
{
public:
void f()
{
std::cout<<"f"<<std::endl;
}
NAME()
{
std::cout<<"default constructor"<<std::endl;
}
NAME(const NAME&)
{
std::cout<<"copy constructor"<<std::endl;
}
};
int main()
{
std::cout << "Hello World" << std::endl;
NAME n;
std::function<void ()> callable = std::bind(&NAME::f, n);
return 0;
}
上述版本1的输出如下:
Hello World
default constructor
copy constructor
copy constructor
我知道传递的参数将被复制,所以复制构造函数应该只被调用一次,但在上面的输出中复制构造函数被调用两次。为什么/如何发生这种情况?是否因为使用 std::bind 创建的新可调用对象将用于在 lhs 上使用 std::function 初始化另一个可调用对象?
第 2 版
int main()
{
std::cout << "Hello World" << std::endl;
NAME n;
std::function<void ()> callable = std::move(std::bind(&NAME::f, n));
return 0;
}
VERSION 2 的输出如下:
Hello World
default constructor
copy constructor
copy constructor
copy constructor
在上面的输出中(对于版本 2),当我使用 std::move 时,为什么/如何调用复制构造函数三次?
版本 3
int main()
{
std::cout << "Hello World" << std::endl;
NAME n;
auto callable = std::bind(&NAME::f, n);
return 0;
}
版本3的输出如下:
Hello World
default constructor
copy constructor
在这种情况下(版本 3)为什么/如何只调用一次复制构造函数?
版本 4
int main()
{
std::cout << "Hello World" << std::endl;
NAME n;
auto callable = std::move(std::bind(&NAME::f, n));
return 0;
}
版本4的输出如下:
Hello World
default constructor
copy constructor
copy constructor
当我们使用 auto 和 std::move() 在这种情况下(版本 4)会发生什么,为什么/如何调用复制构造函数两次。
PS:程序在在线编译器上执行:Online compiler Used
编辑:阅读 cmets 后,我还有一个问题/疑问:
问题 1
如果我使用auto callable_1 = std::bind(&NAME::f, n); 和std::function<void ()> callable_2 = std::bind(&NAME::f, n); 那么callable_1 和callable_2 的类型是否不同?如果是,那么auto 为callable_1 推导出的类型是什么?还是auto 为callable_1 推导出的类型将是一个未命名的类对象,就像lambda 一样。
问题 2
我还有一个问题:正如我在我的案例中所做的那样,如果我在 std::bind 中传递 n 而不是 &n,那么代码是否合法?例如,如果我写 std::function<void ()> callable_1 = std::bind(&NAME::f, n); 和 auto callable_2 = std::bind(&NAME::f, n); 那么这两个都是非法的吗?如果我在这两种情况下都通过ref(n) 而不是n,那么它们是非法的还是合法的?
问题 3
auto callable = [&n]{n.f()}; 和 auto callable = std::bind(&NAME::f, cref(n)); 语句是否等效(在功能上)或者在某些其他方面,除了编码风格之外,是否有任何理由(优势)选择另一个?
问题 4
如果我写auto callable = std::bind(&NAME::f, 1_); callable(n); callable(std::ref(n)); 会怎样。声明callable(n) 是非法的吗?那么callable(std::ref(n));的声明呢。
【问题讨论】:
-
这里的所有问题似乎都围绕着两个主题。 1. -
std::function的开销。 2. - 来自std::move的悲观情绪。 -
附带说明:
NAME::f()需要一个指向对象的NAME*指针作为其this参数,而不是NAME对象本身。所以对std::bind()的调用应该使用&n。然后根本不会复制n:std::bind(&NAME::f, &n) -
@RemyLebeau 是的,我已经知道如果我们在
std::bind中使用&n而不是n,那么根本不会复制。在这种情况下,我的问题是,如果我们像我一样通过n而不是&n,那么代码是否合法? -
@JasonLiam 我想说不,如果
n被复制,f()将不会传递正确的this值。但情况似乎并非如此(除非这是依赖于编译器的行为):ideone.com/MxN29P。另一方面,en.cppreference.com/w/cpp/utility/functional/bind 说:“如Callable中所述,当调用指向非静态成员函数的指针或指向非静态数据成员的指针时,第一个参数必须是引用或指针(可能包括智能指针,例如std::shared_ptr和std::unique_ptr)指向将要访问其成员的对象。"
标签: c++ c++11 bind auto stdbind