我会简短地讲一个很长的故事并举例说明我的问题。
给定一个具有指向基本类型作为属性的指针的类:
@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 *缓冲区以相同的方式处理并且需要具有可变大小,所以我想解决这个问题以解决这个问题。
答案 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;
在这里,bobNumber
和fredNumber
是不同的变量 - 它们具有不同的名称,存在于内存中的不同位置等等 - 恰好具有相同的值。现在,它们具有的值是对内存中另一个位置的引用,因此它们是等效的引用。但是,如果我们更改其中一个会发生什么?
free(fredNumber);
fredNumber = malloc(sizeof(int));
*fredNumber = 7;
由于函数参数是按值传递的,free
不能对fredNumber
本身做任何事情;它只能在fredNumber
的值上运行,释放引用的内存。由于这与bobNumber
的值相同,如果我们尝试取消引用bobNumber
,我们会看到此效果。接下来,我们为fredNumber
分配一个值。由于fredNumber
和bobNumber
生活在内存中的不同位置,因此此分配对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这样的普通值类型。没有任何魔法会导致指向同一地址的两个指针彼此同步。