在不同的对象上调用存储的函数

时间:2017-12-14 14:12:12

标签: c++ c++11

此问题与this answer中的DelayedCaller有关。

DelayedCaller绑定一个函数指针及其参数,并且就像一个魅力一样,只要参数不是指向比DelayedCaller执行更短寿命的指针(认为局部变量的string.c_str()作为参数)

为了避免这个问题,我为扫描参数的模板函数处理的有问题的参数创建了一个存储空间。

我现在需要的是相反的结果:我希望通过将给予DelayedCaller的指针的地址作为参数进行评估,在同一类型的不同对象上调用成员函数。

我目前看到两种方法:

  1. std :: placeholders:在创建DelayedCaller时,它不是提供对象,而是提供调用方法。
  2. 取消引用两次的对象指针的包装器(重载 - >)。
  3. 我赞成2.超过1.(我不想在使用call()时提供参数),但是我甚至没有考虑其他选项。

    示例:

    #include <iostream>
    #include <string>
    #include <functional>
    #include <memory>
    
    class MyClass
    {
        float myFloat;
    public:
        MyClass(float f):myFloat(f){}
    
        void myFunc(int arg1)
        {
            std::cout << arg1 << ", " << myFloat << '\n';
        }
    };
    
    class MyContainer
    {
    public:
        MyClass* object;
    };
    
    // DelayedCaller implementation
    class DelayedCaller
    {
    public:
        template <typename TFunction, typename... TArgs>
        static std::shared_ptr<DelayedCaller> setup(TFunction&& a_func,
                                                    TArgs&&... a_args)
        {
            return std::shared_ptr<DelayedCaller>(new DelayedCaller(
                std::bind(std::forward<TFunction>(a_func),
                          std::forward<TArgs>(a_args)...)));
        }
        void call() const { func_(); }
    
    private:
        using func_type = std::function<void()>;
        DelayedCaller(func_type&& a_ft) : func_(std::forward<func_type>(a_ft)) {}
        func_type func_;
    };
    
    int main()
    {
        MyContainer container;
        MyClass* c1 = new MyClass(45.6);
        container.object = c1;
        // the next line is the critical one. Instead of myFunc being called
        // on the current value of container.object, it should be called on
        // the one container.object is holding when caller is called.
        auto caller(DelayedCaller::setup(&MyClass::myFunc, container.object, 123));
    
        caller->call();
    
        MyClass* c2 = new MyClass(22.8);
        container.object = c2;
        caller->call();
    
        delete c1;
        delete c2;
    
        return 0;
    }
    

3 个答案:

答案 0 :(得分:0)

如何离开&#34;绑定&#34;使用lambda表达式的C ++编译器?

auto caller(DelayedCaller::setup([&container] { container.object->myFunc(123);}));

给出输出:

123, 45.6
123, 22.8

PS。这个lambda可以直接转换为std::function<void(void)>,因此DelayedCaller构造函数可以是公共的,如果需要,可以在没有setup函数的情况下创建。如果你可以编辑它的实现当然。

答案 1 :(得分:0)

std::reference_wrapper可能会有所帮助,请使用:

auto caller(DelayedCaller::setup(&MyClass::myFunc, std::ref(container.object), 123));

Demo

答案 2 :(得分:0)

你真的需要了解std :: bind的作用。

当使用std :: bind时,它将复制(或分别移动它们分别是r值,但作为提醒,它们是否被移动依赖于可调用对象,每个参数都被输入到std ::分别绑定)

接下来,我将讨论当只有一个参数时的情况,但它的规则适用于分别存在多个参数的情况。

可调用对象(可能是函数或函子的指针)和std :: bind返回的std :: function对象的参数,所以在你问的情况下它永远不会出现。

如果参数不是指针或引用,您可以将(临时)对象提供给sts :: bind,而c ++标准承诺只会复制或移动它,而不是通过引用,除非你使用std :: ref或std :: cref来包装那个对象。

但是如果你提供std :: unique_ptr或包装指针的其他东西(或如上所示的引用),你需要将它们视为指针(引用),而不是对象(尽管复制/移动选择仍然发生)

如果参数是指针,那么指针将被复制到其中。

在这种情况下,如果指针指向局部变量bingo,那么你有一个要跟踪的bug。

实际上你编写的代码如果(对象的析构函数不会对内存中的对象造成任何损害,换句话说,对象在被破坏后存在,如POD等) )&amp;&amp; (内存中包含的对象不被任何其他对象重用,当这样的时候(另一个函数被调用,其局部变量占用该对象的内存并向其写入内容)发生它被重用)。

如果指针指向你在堆上分配的并且在你完成对DelayedCaller :: cal的调用之前它没有被释放,那么你的代码没有任何问题。

如果指针是一个指向文字的常量指针,那么一切都会好的。

参数是引用的情况与它是指针的情况大致相同。

参考:http://en.cppreference.com/w/cpp/utility/functional/bind