使用递归块时的 EXC_BAD_ACCESS

发布于 2024-10-15 03:55:57 字数 1715 浏览 2 评论 0原文

我正在尝试使用块创建递归。它工作了一段时间,但最终崩溃并给我一个错误的访问异常。这是我的代码:

BOOL (^Block)(Square *square, NSMutableArray *processedSquares) = ^(Square *square, NSMutableArray *processedSquares) {
    [processedSquares addObject:square];

    if (square.nuked) {
        return YES; // Found a nuked square, immediately return
    }

    for (Square *adjacentSquare in square.adjacentSquares) {
        if ([processedSquares containsObject:adjacentSquare]) {
            continue; // Prevent infinite recursion
        }

        if (Block(adjacentSquare, processedSquares)) {
            return YES;
        }
    }

    return NO;
};

__block NSMutableArray *processedSquares = [NSMutableArray array];
BOOL foundNukedSquare = Block(square, processedSquares);

说明:我有一个 Square 类,它有一个 BOOL nuked。它还有一个包含其他 Square 的 NSArray adjacentSquares

我想检查一个方块或它的“连接”方块之一是否被核武器摧毁。

数组processedSquares用于跟踪我检查过的方块以防止无限递归。

当我运行它时,它会对该块进行大量调用(如预期)。但在某些时候,它会在最后一行崩溃并出现错误的访问异常。

我还在控制台中得到了这个:

无法访问地址 0x1 处的内存
无法访问地址 0x1 处的内存
无法访问地址 0x1 处的内存
无法访问地址 0x1 处的内存
警告:取消调用 - 当前线程堆栈上的 objc 代码会使此操作不安全。

我对块和递归不太熟悉。有什么想法吗?


编辑 1

根据要求,回溯:

#0  0x00000001 in ??
#1  0x000115fb in -[Square connectedToNukedSquare] at   Square.m:105
#2  0x00010059 in __-[Bot makeMove]_block_invoke_1 at Bot.m:94
#3  0x91f3f024 in _dispatch_call_block_and_release
#4  0x91f31a8c in _dispatch_queue_drain
#5  0x91f314e8 in _dispatch_queue_invoke
#6  0x91f312fe in _dispatch_worker_thread2
#7  0x91f30d81 in _pthread_wqthread
#8  0x91f30bc6 in start_wqthread

I'm trying to create recursion using blocks. It works for a while, but eventually it crashes and gives me a bad access exception. This is my code:

BOOL (^Block)(Square *square, NSMutableArray *processedSquares) = ^(Square *square, NSMutableArray *processedSquares) {
    [processedSquares addObject:square];

    if (square.nuked) {
        return YES; // Found a nuked square, immediately return
    }

    for (Square *adjacentSquare in square.adjacentSquares) {
        if ([processedSquares containsObject:adjacentSquare]) {
            continue; // Prevent infinite recursion
        }

        if (Block(adjacentSquare, processedSquares)) {
            return YES;
        }
    }

    return NO;
};

__block NSMutableArray *processedSquares = [NSMutableArray array];
BOOL foundNukedSquare = Block(square, processedSquares);

Explanation: I have a Square class that has a BOOL nuked. It also has an NSArray adjacentSquares containing other Squares.

I want to check whether a square, or one of its 'connected' squares, is nuked or not.

The array processedSquares is to keep track of the squares I have checked to prevent infinite recursion.

When I run this, it's doing a lot of calls of this block (as expected). But at some point, it crashes at the last line with a bad access exception.

I also get this in the console:

Cannot access memory at address 0x1
Cannot access memory at address 0x1
Cannot access memory at address 0x1
Cannot access memory at address 0x1
warning: Cancelling call - objc code on the current thread's stack makes this unsafe.

I'm not that familiar with blocks and recursion. Any ideas?


Edit 1

As requested, the backtrace:

#0  0x00000001 in ??
#1  0x000115fb in -[Square connectedToNukedSquare] at   Square.m:105
#2  0x00010059 in __-[Bot makeMove]_block_invoke_1 at Bot.m:94
#3  0x91f3f024 in _dispatch_call_block_and_release
#4  0x91f31a8c in _dispatch_queue_drain
#5  0x91f314e8 in _dispatch_queue_invoke
#6  0x91f312fe in _dispatch_worker_thread2
#7  0x91f30d81 in _pthread_wqthread
#8  0x91f30bc6 in start_wqthread

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一片旧的回忆 2024-10-22 03:55:57

您需要在 Block 上使用 __block,将声明更改为:

__block BOOL (^Block)(Square *square, NSMutableArray *processedSquares);
Block = ^(Square *square, NSMutableArray *processedSquares) {

当在块内引用变量 (Block) 时,则其当前 value 被复制到块中。在您的代码中,当您在赋值中构造块时,Block 尚未被赋予值...

__block 前缀通过引用传递变量 - 当您的块进行递归调用时,Block 具有一个值,对其的引用将用于获取该值,并且递归调用正常。

我不知道为什么它在没有 __block 的情况下对你有用 - 对我来说直接失败了。然而,使用修饰符,我可以递归到至少 10,000 的深度 - 所以堆栈空间不是问题!

You need a __block on Block, change the declaration to:

__block BOOL (^Block)(Square *square, NSMutableArray *processedSquares);
Block = ^(Square *square, NSMutableArray *processedSquares) {

When a variable (Block) is referenced within a block then its current value is copied into the block. In your code Block hasn't yet been given a value, as you are constructing the block in the assignment...

The __block prefix passes the variable by reference - by the time your block makes its recursive call Block has a value, the reference to it is used to obtain that value, and the recursive call is OK.

I don't know why its worked at all for you without the __block - failed straightaway for me. With the modifier however I can recurse to at least a depth of 10,000 - so stack space isn't a problem!

人事已非 2024-10-22 03:55:57

您喜欢在设置中做一些错误的事情 - 您的 Square 对象可能以某种方式搞砸了。这是一个对我来说效果很好的完整示例,也许它可以帮助您找到错误:

#include <stdio.h>
#include <Foundation/Foundation.h>

@interface Square : NSObject
{
  BOOL nuked;
  NSArray *adjacentSquares;
}

@property(nonatomic) BOOL nuked;
@property(nonatomic, retain) NSArray *adjacentSquares;
@end

@implementation Square

@synthesize nuked;
@synthesize adjacentSquares;

@end;

BOOL (^Block)(Square *square, NSMutableArray *processedSquares) = ^(Square *square, NSMutableArray *processedSquares) {
  [processedSquares addObject:square];

  if (square.nuked) {
    return YES; // Found a nuked square, immediately return
  }

  for (Square *adjacentSquare in square.adjacentSquares) {
    if ([processedSquares containsObject:adjacentSquare]) {
      continue; // Prevent infinite recursion
    }

    if (Block(adjacentSquare, processedSquares)) {
      return YES;
    }
  }

  return NO;
};

int main(int argc, char **argv)
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  Square *s1, *s2;
  s1 = [[Square alloc] init];
  s2 = [[Square alloc] init];
  s1.adjacentSquares = [NSArray arrayWithObjects:s2, nil];
  s2.adjacentSquares = [NSArray arrayWithObjects:s1, nil];

  __block NSMutableArray *processedSquares = [NSMutableArray array];
  BOOL foundNukedSquare = Block(s1, processedSquares);
  printf("%d\n", foundNukedSquare);

  [s1 release];
  [s2 release];

  [pool release];

  return 0;
}

You're liking doing something wrong with the setup -- your Square objects are probably messed up somehow. Here's a complete example that works fine for me, maybe it can help you find your mistake:

#include <stdio.h>
#include <Foundation/Foundation.h>

@interface Square : NSObject
{
  BOOL nuked;
  NSArray *adjacentSquares;
}

@property(nonatomic) BOOL nuked;
@property(nonatomic, retain) NSArray *adjacentSquares;
@end

@implementation Square

@synthesize nuked;
@synthesize adjacentSquares;

@end;

BOOL (^Block)(Square *square, NSMutableArray *processedSquares) = ^(Square *square, NSMutableArray *processedSquares) {
  [processedSquares addObject:square];

  if (square.nuked) {
    return YES; // Found a nuked square, immediately return
  }

  for (Square *adjacentSquare in square.adjacentSquares) {
    if ([processedSquares containsObject:adjacentSquare]) {
      continue; // Prevent infinite recursion
    }

    if (Block(adjacentSquare, processedSquares)) {
      return YES;
    }
  }

  return NO;
};

int main(int argc, char **argv)
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  Square *s1, *s2;
  s1 = [[Square alloc] init];
  s2 = [[Square alloc] init];
  s1.adjacentSquares = [NSArray arrayWithObjects:s2, nil];
  s2.adjacentSquares = [NSArray arrayWithObjects:s1, nil];

  __block NSMutableArray *processedSquares = [NSMutableArray array];
  BOOL foundNukedSquare = Block(s1, processedSquares);
  printf("%d\n", foundNukedSquare);

  [s1 release];
  [s2 release];

  [pool release];

  return 0;
}
他不在意 2024-10-22 03:55:57

您似乎在遍历数组时将 squares 添加到数组中。我说的是这一行:

[processedSquares addObject:square];

这可能与它有关吗?您在遍历时添加一个对象。我很惊讶这竟然有效。

You seem to be adding squares to the array while traversing the array. I'm speaking of this line:

[processedSquares addObject:square];

Might that have to do with it? You're adding an object while traversing. I'm surprised that this works at all.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文