【问题标题】:Constructing std::function target in-place就地构造 std::function 目标
【发布时间】:2015-01-14 22:06:29
【问题描述】:

我理解的std::function的典型用法

#include <iostream>
#include <functional>

using namespace std;

class C {
public: 
    C() { cout << "CREATING" << endl; }
    C(const C&) { cout << "COPY C "<< endl; };
    C(C&&) { cout << "MOVE C " << endl; };
    ~C() { cout << "DELETING"<< endl; }
    C& operator =(const C&) {
        cout << "COPY A " << endl; return *this;
    };
    C& operator =(C&&) {
        cout << "MOVE A" << endl; return *this;
    };
    void operator ()() const { cout << "CALLING" << endl; }
};

int main(int argc, char *argv[]) {
    function<void()> f = C();
    f();
    return 0;
}

产生以下输出

CREATING
MOVE C
DELETING
CALLING
DELETING

显然,临时对象是在堆栈上创建的,然后移动到函数对象中。如果未提供移动构造函数,则改为复制它。
是否有无需临时对象即可设置目标的标准方法?

【问题讨论】:

    标签: c++ c++11 std-function


    【解决方案1】:

    function 从任何函子 F f 构造的方式由 §20.9.11.2.1 中的标准规定为(假设 f 是非空的,强调我的):

    *thisf副本为目标,并以 std::move(f)

    初始化

    所以没有办法就地构造function。这让您可以选择是否采取该行动:

    function<void()> f1 = C{};
    

    或者在 C 周围传递一些更便宜的移动/复制的包装器,无论是您在外部管理的一个:

    C manage_me;
    function<void()> f2 = std::ref(manage_me);
    

    ...或绑定到operator()的分配一个:

    function<void()> f3 = std::bind(&C::operator(), std::make_shared<C>());
    

    如果operator() 恰好过载,最后一个可能会引起一些麻烦,因为您必须将其转换为正确的类型,这是以前的版本都不需要处理的问题。

    function<void()> f4 = std::bind(
                              static_cast<void(C::*)()>(&C::operator()),
                              std::make_shared<C>()
                              );
    

    【讨论】:

      【解决方案2】:

      您可以使用std::bind,但您实际上并不需要为此实现operator()

      int main(int argc, char *argv[]) {
          C c;
          function<void()> f = std::bind( &C::operator(), &c );
          f();
          return 0;
      }
      

      输出:

      CREATING
      CALLING
      DELETING
      

      当然,在这种情况下,您需要正确维护对象 c 的生命周期。 要使std::function 拥有C 实例并使其更加就地构造std::shared_ptr,可以使用:

      int main(int argc, char *argv[]) {
          function<void()> f = std::bind( &C::operator(), std::make_shared<C>() );
          f();
          return 0;
      }
      

      【讨论】:

      • 如果他在做C(),那么无论如何都会限制对象的范围。
      • 当然,这不是使用就地构造,而是根本不使用构造。但仍然值得一提,并且有时可能有用。
      • 好吧,函数对象内部没有构造。 ;-)
      • 如果我必须保持对象的生命周期,为什么不使用function&lt;void()&gt; f = std::ref(C)
      • @5gon12eder 好点,添加了就地构造示例。
      猜你喜欢
      • 1970-01-01
      • 2019-10-19
      • 1970-01-01
      • 1970-01-01
      • 2019-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多