【问题标题】:Objective-C classes, pointers to primitive types, etcObjective-C 类,指向原始类型的指针等
【发布时间】:2026-01-03 16:10:02
【问题描述】:

我会长话短说,并举一个我的问题的例子。

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

@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++ 一样工作?

编辑: 对,一个新鲜的早晨,我可以看到我举了一个非常糟糕的下午 5 点综合症的例子。 我想做的更像是这样的:

@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* 缓冲区以相同的方式处理并且需要具有可变大小,所以我也想解决这个问题。

【问题讨论】:

  • 呃,这是在要求一个充满伤害的世界......并且适当的封装将在您的 -[ClassOne init] 方法中调用 malloc()
  • @DaveDeLong 我很好奇你为什么这么说?我正在为同样的问题而苦苦挣扎,但我什至没有达到 Tobster 的程度。请看这里*.com/questions/12454585/…

标签: objective-c integer pointers storage primitive


【解决方案1】:

您的误解是(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 不会发生任何事情(无论如何这都是无效的,刚刚是freed)。

请注意,您关于“让它像 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 变量——引用需要能够引用某些东西。这可能会产生问题:如果被引用的对象超出范围,则引用的行为是未定义的。

【讨论】:

    【解决方案2】:

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

    销毁一个对象不会自动更新所有指向它的指针,因为这些指针是相互独立的,并且彼此不知道任何信息。

    最好从原始创建一个克隆,而不是共享有问题的对象,这样每个“aNumber”都指向它自己的副本。

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

    弗雷德=鲍勃;

    fred 在哪里创建了 bob 的副本

    在这种情况下,你需要在你的类中使用某种克隆函数。

    编辑:改写

    【讨论】:

      【解决方案3】:

      嗯,据我所知,您的代码完全按照您的指示行事。

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

      【讨论】:

        【解决方案4】:

        这在 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。请记住,指针只是简单的值类型,如整数。没有什么魔法可以使指向同一地址的两个指针相互同步。

        【讨论】:

          最近更新 更多