如何在C++;使用来自ObjC类的std::函数回调? 全局 我有一个C++库,它可以异步工作,包括网络。它有一个特定于达尔文的后端,使用GrandCentralDispatch的C API将工作委托给其他线程。现在,我想通过一层薄薄的ObjC++使用一个新的iOS应用程序编写的库

如何在C++;使用来自ObjC类的std::函数回调? 全局 我有一个C++库,它可以异步工作,包括网络。它有一个特定于达尔文的后端,使用GrandCentralDispatch的C API将工作委托给其他线程。现在,我想通过一层薄薄的ObjC++使用一个新的iOS应用程序编写的库,ios,c++11,asynchronous,objective-c++,Ios,C++11,Asynchronous,Objective C++,我在OSX10.10上使用Xcode 6.3.2 在这个最小的示例中,我重新创建了上述体系结构。问题在于,当操作通过std::function回调返回时,启动异步操作的ObjC类实例不知何故“断开”。只有将std::函数声明为[&]而不是[=]时,才会发生这种情况。我不能使用后者,因为它不被“真实”C++代码支持。 调用ObjC++的Swift代码如下所示: class MyViewController : UIViewController { var test = Objective

我在OSX10.10上使用Xcode 6.3.2


在这个最小的示例中,我重新创建了上述体系结构。问题在于,当操作通过std::function回调返回时,启动异步操作的ObjC类实例不知何故“断开”。只有将std::函数声明为
[&]
而不是
[=]
时,才会发生这种情况。我不能使用后者,因为它不被“真实”C++代码支持。 调用ObjC++的Swift代码如下所示:

class MyViewController : UIViewController {
    var test = ObjectiveTest()

    override func viewDidAppear(animated: Bool) {
        test.testAsyncWork("some data", withHandler: { (result: Int32) -> Void in
            println("Work result: \(result)")
        })
    }
}
handler WorkBlock & error: summary string parsing error 0xbffa50cc
&handler    __block_literal_generic *   0x7c000000  0x0ae08500
__isa   void *  NULL    0x00000000
__flags int 0   0
__reserved  int 2080876705  2080876705
__FuncPtr   void (*)(int)   0x7c000000  0x7c000000
__descriptor    __block_descriptor *    0x7c085b10  0x7c085b10
如果我注释掉代码,视图控制器将显示并保持可见,因此它不应该杀死ObjectiveTest实例。这就是ObjC++粘合层:

@interface ObjectiveTest () {
    __block Test *test;
    __block int _a;
}
@end

@implementation ObjectiveTest
- (id)init
{
    self = [super init];
    if (self) {
        test = new Test();
        _a = 42;
        if (!test)
            self = nil;
    }
    return self;
}

- (void)deinit
{
    delete test;
}

- (void)testAsyncWork:(NSString *)someData withHandler:(WorkBlock)handler
{
    _a++;
    NSLog(@"_a = %i", _a); // valid
    NSLog(@"handler = %@", handler); // valid
    test->testAsyncWork(someData.UTF8String, [&](int result) {
        _a++;
        NSLog(@"result = %i", result); // Expected: "result = 666" - valid
        NSLog(@"_a = %i", _a); // Expected: "_a = 44" - invalid
        NSLog(@"handler = %@", handler); // invalid, crashes here
    });
}
@end
P>最后,做“工作”的C++方法:


从这一点上,我得到的印象是ObjectiveTest实例在过程中的某个地方中断了,但由于它保存在MyViewController中,我不知道这是如何发生的。我可能遗漏了什么吗?

[&]
通过引用捕获变量。如果原始变量在任务完成之前过期,则捕获的引用将挂起

由于异步调用可能旨在异步完成1,因此基本上可以保证挂起引用

在进行异步调用时,您几乎总是希望按值捕获。您甚至可能希望明确列出您捕获的内容,以便了解您引入的依赖项。(如果没有隐藏/隐式依赖项,多线程代码就足够硬了)

[&]
捕获的唯一有效用途是创建一个“访问者”类型的对象,将其传递到将使用lambda的函数中,然后在它返回之前丢弃它及其所有副本。除此之外,您还应该通过价值捕获,或者非常仔细地选择您通过引用捕获的内容,并证明涵盖了生命周期问题



1可能希望
[&]
的异步方法的一个示例是“在UI泵线程上运行”异步调用,在该调用中,您希望工作线程暂停进程,直到结果从UI线程返回。在这里,您要在离开当前作用域之前,阻止返回的
std::future
(或等效值)。

Um,使用
[&]
进行异步调用是一个非常糟糕的主意?它通过引用捕获变量,当您离开当前范围时,它通过引用捕获的变量就消失了。因此,您正在对一组无效的对象进行大量读取。。。你想干什么?确切地说,为什么你认为
[=]
不起作用?要做出响应,请输入一条带有@yakk的注释。
[&]
只适用于一种狭隘的情况,但这涉及到更少的异步,更多的同步。(你想在一个特定的线程上运行某个任务。所以你发送任务,然后阻塞直到任务完成,从而阻止代码前进)。@yakk,你是对的。由于某种原因,当我编写新代码时,我一直在想“<代码> [/]代码],而在C++代码中我也这样做。我确实理解其中的区别,一定是我的大脑不喜欢
[=]
。。。如果你把它作为答案贴出来,我会接受的。:)此外,这里通过引用捕获没有意义,因为捕获的变量(
self
handler
)都没有分配给任何一个,所以通过值捕获是等效的和更好的。此外,您从不使用
\u block
声明实例变量。这是无用的,最好是编译器错误<代码>\u块仅对局部变量有任何意义,因为这些是唯一可以“捕获”的变量。此外,捕获的引用可能应该很弱,以避免引用循环和对象泄漏的可能性。请注意,objective-C块通过const copy隐式捕获块中使用的任何内容(这会导致对已引用计数的objective-C对象进行引用)。您可能会意外地通过复制在操作间代码中捕获
self
-或更糟的
。我还建议您避免使用C++11 lambda的
[&]
[=]
捕获所有按引用/值表示法,并显式列出捕获。使用<代码> STD::VistuxPTR 将C++对象传递给块。
handler WorkBlock & error: summary string parsing error 0xbffa50cc
&handler    __block_literal_generic *   0x7c000000  0x0ae08500
__isa   void *  NULL    0x00000000
__flags int 0   0
__reserved  int 2080876705  2080876705
__FuncPtr   void (*)(int)   0x7c000000  0x7c000000
__descriptor    __block_descriptor *    0x7c085b10  0x7c085b10