Objective-C类,原始类型的指针等

时间:2010-04-15 16:00:28

标签: objective-c integer pointers storage primitive

我会简短地讲一个很长的故事并举例说明我的问题。

给定一个具有指向基本类型作为属性的指针的类:

@interface ClassOne : NSObject
{
int* aNumber
}

@property int* aNumber;

该类被实例化,并且aNumber被分配并分配一个值,相应地:

ClassOne* bob = [[ClassOne alloc] init];
bob.aNumber = malloc(sizeof(int));
*bob.aNumber = 5;

然后通过引用传递,以相应地分配此类类别的单独实例的aNumber值:

ClassOne* fred = [[ClassOne alloc] init];
fred.aNumber = bob.aNumber;
然后释放,重新分配Fred的aNumber指针,并为其分配一个新值,例如7。

现在,我遇到的问题; 由于Fred被分配了与Bob相同的指针,我希望Bob的aNumber现在的值为7.它没有,因为由于某种原因它的指针被释放,但没有重新分配(它仍然指向它首先被分配的相同地址现在被释放了。 但是,Fred的指针在不同的内存位置具有分配值7。

为什么会这样?我什么是误解?我怎样才能让它像C ++一样工作?

编辑: 是的,一个清新的早晨,我可以看到我给了一个非常糟糕的,5pm综合症的例子。 我想要做的更像是这样:

@interface classOne : NSObject
{
    int* numA;
}
@property int* numA;

@implementation...etc

为numA分配并分配一个值。稍后,在一个单独的线程(带有必要的锁等)中,这样做:

int* numB= malloc(sizeof(int));
*numB = 5;  
free(RefToClassOne.numA);
RefToClassOne.numA = numB;

numA确实被释放,但没有被赋予numB指向的值,这就是我想要的行为。

较长的故事的一部分是它是传递给openGL的顶点缓冲区的一部分的顶点计数。我意识到它不应该是一个指针,但是坐标的float *缓冲区以相同的方式处理并且需要具有可变大小,所以我想解决这个问题以解决这个问题。

4 个答案:

答案 0 :(得分:3)

你误解的是:(a)你不能在Objective-C中通过引用传递东西,(b)即使你可以,也不会在这里帮助你。

Objective-C只允许您按值传递内容。有时,如对象或指针的情况,您传递的值是本身一个引用,但它被视为一个值。 C ++ - 样式透明引用不存在。

但假设我们拥有它们。在这种情况下,这会有什么帮助? aNumber实例变量仍为int*类型;当您分配给它时(如在fred.aNumber = bob.aNumber中),您必须创建一个副本。此时,通过引用传递的内容并不重要,事物变量也不重要。您的代码实际上与

相同
int* bobNumber;
int* fredNumber;

bobNumber   = malloc(sizeof(int));
*bobNumber  = 5;
fredNumber  = bobNumber;

在这里,bobNumberfredNumber是不同的变量 - 它们具有不同的名称,存在于内存中的不同位置等等 - 恰好具有相同的值。现在,它们具有的值是对内存中另一个位置的引用,因此它们是等效的引用。但是,如果我们更改其中一个会发生什么?

free(fredNumber);
fredNumber  = malloc(sizeof(int));
*fredNumber = 7;

由于函数参数是按值传递的,free不能对fredNumber本身做任何事情;它只能在fredNumber的值上运行,释放引用的内存。由于这与bobNumber的值相同,如果我们尝试取消引用bobNumber,我们会看到此效果。接下来,我们为fredNumber分配一个值。由于fredNumberbobNumber生活在内存中的不同位置,因此此分配对bobNumber自然无效。此时,fredNumber != bobNumber,当我们将7分配给*fredNumber时,*bobNumber没有任何反应(无论如何,这只是free d )。

请注意,您对“让它像C ++一样工作”的评论很奇怪;像我说的那样,C ++也不会这样。如果你真的想在C ++中使用它,你必须有一个引用实例变量

class ClassTwo {
  public:
    int*& aNumber;
    ClassTwo(int*& an) : aNumber(an) { }
};

请注意,an需要通过引用传递;我原本试图在没有它的情况下做到这一点,然后在构造函数中创建了一个副本,产生了同样的旧问题。

现在,无论我们是否通过引用传递bob,它仍将具有相同的aNumber引用,因此我们可以构建类似

的内容
int* shared;
ClassTwo bob(shared);
bob.aNumber = new int(5);
ClassTwo fred(bob.aNumber);
delete fred.aNumber;
fred.aNumber = new int(7);

一切都会像你期望的那样发挥作用。但是,这可能不是一个好主意。出于一个原因,请注意shared变量引用需要能够引用某些内容。这会产生问题:如果被引用的对象超出范围,则引用的行为是未定义的。

答案 1 :(得分:0)

如果将两者都设置为指向同一个对象,则在释放对象时,您实际上会删除两者指向的对象,因此两个指针都变为无效。为了重新分配,您需要通过将两个指针设置为指向同一个新对象来重复相同的过程。

销毁对象不会自动更新指向它的所有指针,因为指针彼此独立且彼此不知道。

最好通过从原始克隆创建克隆而不是共享相关对象,以便每个'aNumber'指向其自己的副本。

我猜你所追求的就像用C ++编写的那样

fred = bob;

fred创建bob的副本

在这种情况下,你需要在你的班级中使用某种克隆功能。

编辑:改写

答案 2 :(得分:0)

好吧,据我所知,你的代码完全按照你所说的去做。

使用指向int的指针不是处理值的最兼容方式;你需要适当地调用它,如果你只想在对象之间传递值,那么使用NSValue对象会更加简单。

答案 3 :(得分:0)

这在C ++中的工作方式相同。这是一个等效的例子:

class Bob {
    public:
    int *aNumber;
};

void wontWork() {
    Bob bob, fred;
    bob.aNumber = new int;
    *bob.aNumber = 5;
    fred.aNumber = bob.aNumber;
    delete fred.aNumber;
    fred.aNumber = new int;
    *fred.aNumber = 7;
    cout << *bob.aNumber << *fred.aNumber << endl;
}

你认为* bob.aNumber在这里是7吗?当你做delete fred.aNumber时,它释放了bob和fred所指向的记忆。然后你重新分配fred指向新内存,但是你没有重新分配bob,所以它只是一个悬空指针。所以没有任何东西会导致bob成为7.记住,指针只是像int这样的普通值类型。没有任何魔法会导致指向同一地址的两个指针彼此同步。