Objective C 在堆栈上分配对象

问题描述 投票:0回答:7

我是 Objective C 的新手,正在做一些对象练习。虽然像

Fraction* f = [[Fraction alloc] init ];
这样的东西有效,但每当我尝试做
Fraction c;
时,我都会得到
Interface type cannot be statically allocated
是否有在堆栈上分配对象的方法(就像在 c++ 中一样)?或者我尝试了错误的事情?

objective-c object stack
7个回答
6
投票

从技术上讲,你可以(参见下面的代码),但你不应该。而且,无论是在栈还是堆中,你只有一个指向对象的指针,而不是对象本身。也就是说,您应该写

Fraction *c
,而不是
Fraction c

// Allocate an Objective-C object on the stack.
// Original code By Graham Lee: 
// https://gist.github.com/iamleeg/5290797     

#import <Foundation/Foundation.h>
#include <stdlib.h>
#include <objc/runtime.h>

@interface A : NSObject
@property (assign) int meaning;
@end

@implementation A

- (id)init {
    if ([super init]) {
        _meaning = 42;
    }
    return self;
}

@end


int main(int argc, char *argv[]) {
    @autoreleasepool {

        // allocate and zero stack memory
        size_t size = class_getInstanceSize([A class]);
        id obj = (__bridge_transfer id) alloca(size);
        memset((__bridge void*)obj, 0, size);

        // set class and initialize the object
        object_setClass(obj, [A class]);
        obj = [obj init];

        NSLog(@"meaning: %d", [obj meaning]);

        // transfer ownership from ARC to CF so ARC doesn't 
        // try to improperly free the stack allocated memory
        CFTypeRef ref = (__bridge_retained CFTypeRef) obj;
    }
}

alloca()
是非标准的、不安全的、不可移植的,并且容易出现堆栈溢出。


4
投票

您无法在 Objective C 中静态分配对象。造成这种情况的原因有很多。包括对象应该被初始化,但初始化方法允许改变对象的地址。

在 C++ 中,构造函数必须初始化它所调用的对象,并且不能以任何方式更改对象地址。在 Objective C 中情况并非如此。构造函数的等效项(alloc+init* 序列或类级别方法)可以决定它们将更改它们所调用的对象的地址(它们将处理当然,释放原始对象)。

当然,他们无法释放静态分配的内存,也无法更改堆栈的地址。


1
投票

不,所有对象都分配在 Obj-C 的堆上。


1
投票

不,你不能使用堆栈作为 Objective-C 对象的内存,它必须是堆(通过

alloc
init
)。

虽然,正如@wattson12所指出的,您显然可以将对象引用(指针)存储在堆栈上,但这仍然不使用堆栈作为对象的内存。


1
投票

@Jano 解决方案的另一种方法,使用:

  • 通过相同大小的结构的普通 C 内存堆栈(而不是使用
    class_getInstanceSize(…)
    malloca(…)
  • Obj-C MRR 模式 (禁用 ARC,如果你敢于堆栈分配 Obj-C 对象,你真的应该仔细手动检查应用程序/库中的每个保留/释放)
#import <Foundation/Foundation.h>
#include <objc/runtime.h>
#include <malloc/malloc.h>

@interface A : NSObject
@property (assign) int meaning;
@end

@implementation A

- (id)init {
    if ([super init]) {
        _meaning = 42;
    }
    return self;
}

- (void)dealloc
{
    BOOL wasStackAllocated = (malloc_zone_from_ptr(self) == NULL);
    if (!wasStackAllocated)
        [super dealloc];
}

@end


struct A_storage {
    uint8 bytes[16];
};





int main(int argc, char *argv[]) {
    @autoreleasepool {
        
        // allocate and zero stack memory
        assert(class_getInstanceSize(A.class) == sizeof(struct A_storage));
        struct A_storage obj_storage;
        id obj = (id)&obj_storage;
        memset(obj, 0, sizeof(struct A_storage));
        
        // set class and initialize the object
        object_setClass(obj, [A class]);
        obj = [obj init];
        
        NSLog(@"meaning: %d", [obj meaning]);
        
        // Pass `obj` to other code here, as long as you make sure those objects are
        // released and aren't holding any refs before continuing.
        
        [obj release];
        assert([obj retainCount] == 0);
    }
}

警告:这是非常疯狂且不受支持的行为,谁知道有什么警告,但是 Obj-CDarwin 的 malloc 是开源的,因此您需要阅读并理解幕后发生的情况(如果/何时)这在实际的应用程序/库使用中会严重崩溃。


0
投票

所有 Objective-C 对象都分配在 heap 中,除了块对象。主要原因是:

  1. Objective-C 中不跟踪指向对象的指针(相反 Objective-C 使用引用计数系统进行内存管理);如果您移动对象,它们将无法更新。
  2. 当创建它们的函数返回时,
  3. stack对象将被销毁。

Mike Ash 的帖子有助于理解这一点。


-1
投票

您收到的错误是由于语法错误,您需要执行以下操作:

Fraction *c; 

注意缺少 * 表示这是一个指向对象的指针(您没有将此对象存储在堆栈上,您只是创建对(潜在)对象的引用)

© www.soinside.com 2019 - 2024. All rights reserved.