开发者

Objective-C classes, pointers to primitive types, etc

开发者 https://www.devze.com 2022-12-27 05:10 出处:网络
I\'ll cut a really long story short and give an example of my problem. Given a class that has a pointer to a primitive type as a property:

I'll cut a really long story short and give an example of my problem.

Given a class that has a pointer to a primitive type as a property:

@interface ClassOne : NSObject
{
int* aNumber
}

@property int* aNumber;

The class is instantiated, and aNumber is allocated and assigned a value, accordingly:

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

It is then passed, by reference, to assign the aNumber value of a seperate instance of this type of class, accordingly:

ClassOne* fred = [[ClassOne alloc] init];
fred.aNumber = bob.aNumber;

Fred's aNumber pointer is then freed, reallocated, and assigned a new value, for example 7.

Now, the problem I'm having; Since Fred has been assigned the same pointer that Bob had, I would expect that Bob's aNumber will now have a value of 7. It doesn't, because for some reason it's pointer was freed, but not reassigned (it is still pointing to the same address it was first allocated which is now freed). Fred's pointer, however, has the allocated value 7 in a different memory location.

Why is it behaving like this? What am I minsunderstanding? How can I make it work like C++ does?

Edit: Right, a fresh morning and I can see I gave a really bad, 5pm syndrome example. What I'm trying to do is more like this:

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

@implementation...etc

numA is alloced and assigned a value. Later on, in a seperate thread (with necessary locks etc), this is done:

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

numA does get freed, but does not get assigned the value that numB is pointing to, which is the behaviour I would like.

Part of the longer story is that it is the vertex count for part of a vertex buffer that is passed into openGL. I realise that it shouldn't be a pointer, but the float开发者_如何学运维* buffer for the coordinates is dealt with in the same way and needs to be of variable size, so I want to fix this to solve that problem also.


What you are misunderstanding is that (a) you cannot pass things by reference in Objective-C, and (b) even if you could, it wouldn't help you here.

Objective-C only allows you to pass things by value. Sometimes, as in the case of objects or pointers, the value you are passing is itself a reference, but it's being treated as a value. C++-style transparent references don't exist.

But suppose that we had them. How would that help in this case? The aNumber instance variable is still of type int*; when you assign to it (as in fred.aNumber = bob.aNumber), you must create a copy. At this point, it doesn't matter what was passed by reference, and nor does it matter that things are instance variables. Your code is effectively the same as

int* bobNumber;
int* fredNumber;

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

Here, bobNumber and fredNumber are different variables—they have different names, live at different locations in memory, etc.—that happen to have the same value. Now, the value they have is a reference to another location in memory, so they are equivalent references. However, what happens if we change one of them?

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

Since function arguments are passed by value, free can't do anything to fredNumber itself; it can only operate on fredNumber's value, freeing the referenced memory. Since this is the same as bobNumber's value, we see this effect if we try to dereference bobNumber. Next, we assign a value to fredNumber. Since fredNumber and bobNumber live at different locations in memory, this assignment naturally does nothing to bobNumber. At this point, fredNumber != bobNumber, so naturally when we assign 7 to *fredNumber, nothing happens to *bobNumber (which is invalid anyway, having just been freed).

Note that your comment about "making it work like C++ does" is strange; C++, like I said, doesn't work this way either. If you really wanted to make this work in C++, you would have to have a reference instance variable

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

Note that an needs to be passed by reference; I originally tried to do it without that, and then a copy was created in the constructor, producing the same old set of problems.

Now, whether or not we pass bob by reference, it will still have the same aNumber reference, so we can construct something like

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

And everything will work like you expect. However, this may well not be a good idea. For one reason why, note the shared variable—references need to be able to reference something. And this can produce problems: if the object being reference goes out of scope, the behavior of the reference is undefined.


If you set both to point to the same object then when you free the object you are effectively removing what both are pointing to so both pointers become invalid. In order to reassign you need to repeat the same procedure by setting both pointers to point to the same new object.

Destroying an object will not automatically update all pointers that point to it since the pointers are independent from each other and don't know anything about each other.

You are better off by creating a clone from the original instead of sharing the object in question so that each 'aNumber' points to its own copy.

I guess what you are after is like in C++ you write

fred = bob;

where fred creates a copy of bob

in that case you would need some kind of clone function in your class.

EDIT: rephrased


Well, as far as I can see your code is doing exactly what you are telling it to.

Using a pointer to an int isn't the most compatible way of handling a value; you will need to call free on it appropriately, and it would strike me as far simpler to use a NSValue object if you just want to pass the value between objects.


This works the same way in C++. Here's an equivalent example:

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;
}

Do you expect *bob.aNumber to be 7 here? When you did delete fred.aNumber, that freed the memory that both bob and fred pointed to. Then you reassigned fred to point to new memory, but you did not reassign bob, so it's just a dangling pointer. So there's nothing that would cause bob to be 7. Remember, pointers are just plain value types like ints. There's no magic that causes two pointers pointing to the same address to sync up with each other.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号