【问题标题】:std::bind vs std::shared_ptrstd::bind 与 std::shared_ptr
【发布时间】:2014-03-25 23:11:21
【问题描述】:

无法理解如何使用绑定到类函数的 shared_ptr。 USE 行发生错误,因为编译器无法将 shared_ptr 转换为 A

#include <functional>

class A {
    public:
        const bool check(void) const { return true; };
};

int _tmain(int argc, _TCHAR* argv[]) {
    const std::function<const bool(const A)> f_check = &A::check;
    auto a = std::make_shared<const A>();
    auto f_check_a = std::bind(f_check, a); // line BIND
    auto res = f_check_a(); // line USE - ERROR!!!

    return 0;
}

我可以替换 BIND 行来访问智能指针的实际值:

int _tmain(int argc, _TCHAR* argv[]) {
    auto f_check = &A::check;
    auto a = std::make_shared<const A>();
    auto f_check_a = std::bind(f_check, *a.get()); // line BIND
    auto res = f_check_a(); // line USE - NO ERRORS

    return 0;
}

现在代码已编译,可能会起作用。 但我想知道 - 使用智能指针的原始值是否可以接受?我可以以某种方式使用 shared_ptr 代替原始值吗?

UPD2: 看来我的同事找到了一个不错的解决方法:

class A {
    public:
        const bool check(void) const { return true; };
};

using p_func = const bool(A::*)() const;

int _tmain(int argc, _TCHAR* argv[]) {
    auto a = std::make_shared<const A>();
    p_func b = &A::check;
    auto f_check_a = std::bind(b, a);
    auto res = f_check_a();
}

现在我可以发送 b 作为参数并绑定到 shared_ptr

统一更新: 我不能在我的实际任务中使用 lambda。 以下是来自真实项目的更多代码:

#include <functional>
#include <algorithm>

class Block {
    public:
        const bool check1(void) const { return false; };
        const bool check2(void) const { return false; };
        const bool check3(void) const { return false; };
};

using block_t = std::shared_ptr<const Block>;

class Worker {
    private:
        std::vector<const block_t> _container;
    public:
        void processor(const std::function<const bool(const Block)> f_check) {
            block_t my_block = nullptr;
            auto lambda = [my_block, f_check](const block_t block) mutable {
                auto function_check = std::bind(f_check, *block.get());
                if (function_check()) {
                    my_block = block;
                    return true;
                }
                return false;
            };
            std::find_if(_container.begin(), _container.end(), lambda);
        }
};

void test(block_t block) {
    Worker worker;
    worker.processor(&Block::check1);
    worker.processor(&Block::check2);
    worker.processor(&Block::check3);
}

UPD3: 修复了没有智能指针取消引用的代码:

#include <functional>
#include <algorithm>

class Block {
public:
    const bool check1(void) const { return false; };
    const bool check2(void) const { return false; };
    const bool check3(void) const { return false; };
};

using block_t = std::shared_ptr<const Block>;
using p_func = const bool(Block::*)() const;

class Worker {
private:
    std::vector<const block_t> _container;
public:
    void processor(p_func f_check) {
        block_t my_block = nullptr;
        auto lambda = [my_block, f_check](const block_t block) mutable {
            auto function_check = std::bind(f_check, block);
            if (function_check()) {
                my_block = block;
                return true;
            }
            return false;
        };
        std::find_if(_container.begin(), _container.end(), lambda);
    }
};

void test(block_t block) {
    Worker worker;
    worker.processor(&Block::check1);
    worker.processor(&Block::check2);
    worker.processor(&Block::check3);
}

【问题讨论】:

  • 我不明白为什么不能用 lambda 替换 std::bind 行。
  • 我在调用方法 check1..3 时没有对象实例,在客户端我只能发送对应该处理集合的类函数的引用。
  • 你会的。 block 还有什么?只需将 lambda 嵌套在另一个 lambda 中。
  • 对不起,我需要一些时间来理解你的意思
  • 为什么要使用bind?直接说if (f_check(*block))吧!

标签: c++ c++11 bind std shared-ptr


【解决方案1】:

您的问题是您首先从成员函数创建一个std::function,期望一个A 实例,然后尝试将其绑定到shared_ptr。你可以跳过那部分:

auto a = std::make_shared<const A>();
auto f_check_a = std::bind(&A::check, a);
auto res = f_check_a(); 

std::bind 知道如何将成员函数直接绑定到shared_ptr

【讨论】:

  • @adnako Strange,用 MSVC 2010 测试并编译。
  • 对不起,它真的很好用。现在我需要将其修改为我的真实用例。谢谢。
【解决方案2】:

您必须使用std::bind 吗?您可以改用 lambda。

auto f_check_a = [=]{ return a->check(); };

【讨论】:

  • 我发布了更多代码,请检查一下。在我的情况下,我不能使用 lambda。
【解决方案3】:

function 期望得到A 的实例,而不是shared_ptr&lt;A&gt;,所以我相信你的问题的答案基本上是肯定的。

但是,我将对您的代码进行 2 处更改,如下所示(请参阅我的 cmets):

const std::function<const bool(const A&)> f_check = &A::check; // <-- Added & after A here
auto a = std::make_shared<const A>();
auto f_check_a = std::bind(f_check, *a); // <-- no need to call get() on a
auto res = f_check_a(); // line USE - ERROR!!!

【讨论】:

  • "
【解决方案4】:

但我想知道 - 使用来自智能指针的原始值是否可以接受?

是的,但您可以只写*a 而不是*a.get()

但是,从bind 返回的调用包装器具有对A 对象的引用,因此您有责任确保该引用保持有效。如果您绑定了shared_ptr,那么这将增加引用计数并保持对象处于活动状态。

我可以用 shared_ptr 代替原始值吗?

如果你使用std::function&lt;const bool(const A)&gt;,那么你不能传递shared_ptr&lt;const A&gt;

当您使用std::function&lt;const bool(const A)&gt; 时,您会创建一个具有完全调用签名const bool(const A) 的可调用类型,因此您必须向它传递一个可转换为const A 的参数,并且shared_ptr&lt;const A&gt; 不能转换为@987654332 @。

一种解决方法是使用 lambda 组合 std::functionshared_ptr

            auto function_check = [] { return f_check(*block); };
            if (function_check()) {

但是,您正在尝试解决一个不应该存在的问题,只需这样做:

            if (f_check(*block)) {
                my_block = block;
                return true;
            }
            return false;

那么你不需要bind 任何东西。

【讨论】:

  • 是的,如果我使用解引用,我可以抛出绑定,例如谢谢。但我只是想避免任何关注指针生命周期的责任。看来我找到了解决方案,请查看 UPD3
  • UPD3 中的 bind 仍然没用。 std::mem_fn(f_check)(*block) 也可以,或者只是((*block).*f_check)()。我不明白您为什么对取消引用有恐惧症,为什么要使代码复杂化以避免它? block 被传递给闭包函数,它的生命周期不会在你取消引用它之前结束。你在担心什么?
  • 因为解引用对我来说很痛苦,而且我对 c++ 中的内存管理没有足够的知识和经验。我确信智能指针在取消引用空指针方面没有问题,而且我有很多经典指针访问冲突的例子。我会考虑两种方式。感谢您的建议。
  • “因为解除引用对我来说很痛苦” O_o wut?如果指针为空,那么bind 版本仍然会取消引用它并崩溃,只是取消引用发生在库代码中而不是在您的代码中。
  • 智能指针在我的情况下不能为空,因为我遵循简单的规则。如果 STL 需要取消对 SP 的引用,则可以确定我的 SP 是有效的,并且不会由于 “指针为空” 而导致崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-27
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多