【问题标题】:Using std::bind with member function, use object pointer or not for this argument?将 std::bind 与成员函数一起使用,是否为该参数使用对象指针?
【发布时间】:2013-02-22 05:27:03
【问题描述】:

使用std::bind绑定成员函数时,第一个参数是对象this指针。但是,它可以将对象作为指针而不是作为指针传递。

例如看下面的程序:

#include <iostream>
#include <functional>

struct foo
{
    void bar(int v) { std::cout << "foo::bar - " << v << '\n'; }
};

int main()
{
    foo my_foo;

    auto f1 = std::bind(&foo::bar, my_foo, 1);
    auto f2 = std::bind(&foo::bar, &my_foo, 2);

    f1();
    f2();
}

clang 和 GCC 都毫无怨言地编译它,结果对两个绑定都有效:

富::酒吧 - 1 富::酒吧 - 2

我一直试图围绕规范(第 20.8.9 节)展开思考,但这是我不太清楚的地方之一。

应该只有一个正确,还是两个都正确?

【问题讨论】:

  • Scott 的“新 c++ 概述”幻灯片 216,说两种方法都是正确的。除非 my_foo 是 unique_pointer,否则需要用 std::ref 包装,并且它不适用于弱指针
  • Scott 的概述(在最新幻灯片的第 221 页上)还说您可以使用 std::moveunique_ptr 将所有权转移到 bind 返回的可调用对象中。它不适用于weak_ptr,因为您不能取消引用weak_ptr
  • 请注意,在 f1 示例中,my_foo 被复制。这不适用于不可复制的对象。如果删除 foo 的拷贝 ctor,这段代码将无法编译。
  • @Jean-BernardJansen 很高兴提到不同之处。

标签: c++ c++11 language-lawyer


【解决方案1】:

两者都是正确的。 20.8.9.1.2 转发到 20.8.2 以描述您对bind 的调用的要求和效果。 20.8.2 是:

20.8.2 要求 [func.require]

1 定义INVOKE(f, t1, t2, ..., tN)如下:

(t1.*f)(t2, ..., tN)f 是指向类T 的成员函数的指针并且t1T 类型的对象或对T 类型对象的引用或引用时到从T派生的类型的对象;

——((*t1).*f)(t2, ..., tN)f 是指向类T 的成员函数的指针并且t1 不是上一项中描述的类型之一时;

t1.*fN == 1f 是指向类T 的成员数据的指针并且t1T 类型的对象或对T 类型的对象的引用或对派生自T 的类型的对象的引用;

——(*t1).*fN == 1f 是指向类的成员数据的指针Tt1 不是上一项中描述的类型之一;

——在所有其他情况下为f(t1, t2, ..., tN)

前两个选项允许引用和指针。

这里要注意的重要一点是,措辞确实将您限制为纯指针。您可以使用std::shared_ptr 或其他一些智能指针来保持您的实例在绑定时保持活动状态,并且它仍然可以与std::bind 一起使用,因为t1 被取消引用,无论它是什么(当然,这是可能的) .

【讨论】:

  • 当我的实例是静态变量时,只有第二种(传递指针)方法对我有用。第一种方法导致每个绑定都像给定另一个实例一样工作;也就是说,如果 f1 和 f2 连续运行,都使用第一种方式绑定,那么 f1 对静态实例的副作用在调用 f2 时不会显示
  • 啊,我现在看到当我没有传递指针时,我正在将我的静态实例复制到一个新实例。这就是我不遵守五法则的结果
【解决方案2】:

添加到正确答案(两种形式都允许)。

我认为这两个绑定选项类似于函数参数声明,可能是“按值传递”或“按引用传递”。

f1 的情况下(又名“按值”传递my_foo),结果不会“看到”通过绑定点对my_foo 所做的任何更改。如果my_foo 发展,这可能不是我们所希望的。 “按值”绑定需要(多次)调用复制构造函数的额外“成本”。

【讨论】:

    【解决方案3】:

    有区别。正如 rytis 提出的,按值传递不会看到对 my_foo 所做的更改。例如,如果 my_foo 是一个类,按值传递不会看到对 my_foo 的成员数据所做的更改。

    【讨论】:

      猜你喜欢
      • 2016-10-04
      • 1970-01-01
      • 1970-01-01
      • 2011-09-27
      • 2012-10-28
      • 2018-08-08
      • 1970-01-01
      • 2015-12-11
      • 1970-01-01
      相关资源
      最近更新 更多