For example if I have an object that contains a pointer to a dynamically allocated object, then assign it to another object with the same type, i.e.
object2 = object1;
and the destructor will explicitly delete the dynamically allocated object. So when object2 and object1 go out of scope, an error will occur (which I assume to be because the address for the dynamically allocated object is deleted twice). So what should I do to fix/avoid this problem?
I'm guessing this is C++? In which case, take a look at smart pointers. Reference counting (boost::shared_ptr) helps take care of this sort of problem.
You cannot avoid it because you copied all bits of object1 to object2, there will be two pointers to the same place, but the destructor will be called twice, because there are two objects.
The fisrt solution will prevent the call of the destructor of object2:
char object2_data[sizeof(object1)];
Type* object2 = (Type*) object2_data;
*object2 = object1;
...
object1.do_something();
object2->do_something(); //However, the pointer is different
The second way is to redesign the object and add a bool variable that will tell if the object is a copy. When the object be deleted, if it is a copy, do not delete the pointer. Finally, implement the copy constructor and overload the operator = to copy the object and set the bool variable to tell that it is a copy. However, if the original object be deleted, the copies will not can be used, because they will have invalid pointers.
Related
Suppose I have an object, for example an NSString, with retain count 5. When I call copy on it, I get a new copy of the object; does this new object have the retain count of its original object ?
It depends. copy is a convenience method for copyWithZone:,
and the "NSCopying Protocol Reference" states:
Your options for implementing this protocol are as follows:
Implement NSCopying using alloc and init... in classes that don’t
inherit copyWithZone:.
Implement NSCopying by invoking the
superclass’s copyWithZone: when NSCopying behavior is inherited. If
the superclass implementation might use the NSCopyObject function,
make explicit assignments to pointer instance variables for retained
objects.
Implement NSCopying by retaining the original instead of
creating a new copy when the class and its contents are immutable.
(I have modified the following two statements after all that feedback.)
For example, NSString is an immutable object, and copy just retains the object
and returns a pointer to the same object. Retaining the object might increase the
retain count, but not necessarily (as in the case of string literals.)
Copying an NSMutableString would probably create a new object and return that.
The new object would have its own retain count independent of the original object.
But you should not care about the difference. With manual reference counting,
copy returns an object that you own and have to release eventually.
With ARC, the compiler with automatically handle that.
copy returns an object that is a semantic [shallow] copy(1) of the object. What the copy method returns is an implementation detail; it may return the same object, it may return a different instance of the same class, or it might even return an instance of a different class.
Doesn't matter.
What matters is that the returned object, under manual retain/release, has a retain count of +1. Not 1, but +1. It might actually be 1, 42, 981, or -1. Doesn't matter.
All that matters is that you must balance that retain with a release or autorelease somewhere if you want to relinquish the object back to the system. Which may not actually cause it to be deallocated; that is an implementation detail of no concern (until optimization time, anyway).
(1) semantic [shallow] copy means that the object returned is an effective shallow copy. The state contained within the copied object (but not within objects contained within the object -- that is the shallow part) will not change when the original object changes state. For a mutable object, copy must actually create a new instance of some object -- most likely an immutable variant class -- that can contain the original state.
For an immutable object, the copy method might be simply implemented as return [self retain];. Or, in the case of static NSStrings (NSCFStrings), it might simply be return self; as retain/release/autorelease are no-ops on such strings.
No, a copied object will have a retain count of 1, just like a newly initialized object.
I highly recommend you read the Memory Management Guide if you wish to learn more.
If you're new to iOS development, the iOS App Programming Guide should be read first, and is a great use of your time.
I just noticed you didn't tag this as iOS specific, if you're coding for Mac, the Programming with Objective-C guide might be more appropriate for you.
To really get your head around this issue, don't think in terms of retain count, think in terms of pointer ownership (like ARC does).
If an object has a "retain count" of 5, that means five pieces of code somewhere are each holding a (strong) pointer to its memory address. If you copy that object, you get a pointer to the address of the new, copied object. The other five pieces of code are still pointing to the original object. There's only one piece of code pointing to the new object, so its "retain count" is one.
As noted in other answers, the Memory Management Guide definitely helps make this all clear.
Why did I put "retain count" in quotes? Because it's only useful as a general concept -- you shouldn't be using retainCount directly, or you'll hear from #bbum.
Objective-C plays some clever tricks when you ask it to copy objects, and as a result retain counts might not be what you think they should be.
Let's say you have an object pointer x with a retain count of n, and call the copy method which returns an object pointer y.
NSObject* x = ...;
NSObject* y = [x copy];
Then the rule is that if you release x n times, and release y once, all objects will be gone. Usually this is achieved by leaving x unchanged, and giving y a retain count of 1.
However, if x points to an immutable object, then Objective-C may decide that no copy needs to be done. The result is that y = x. Still, the rule above still applies: Releasing x n times and y once (even though they are the same object) will free all the objects involved. That's achieved by the copy method returning x with a +1 retain count.
Copy on mutable object like NSMutableArray will create a new copy and retain count will be 1 while copy immutable object like NSArray will point to same reference and increase the retain count by 1.
I am having problem with understanding one concept of memory managment, because I am new to objective C. For instance lets say I have a class Bar and Foo.
in main function I call:
Foo *foo = [bar getFoo]; //In my bar method I return foo
[foo retain];
[foo callMethod];
[foo release];
I know this is right way to do it. But why do we have to retain it after we get it from another object, does not this mean returning object has retain count 0 ? so we have to reatin it to count 1 to use it? but if it has reatin count 0, how do we know it is still there. We can assume since it is the next line that increment retain count that the object memory wont be realocated, but what if we have multi-threading program?
When an class method returns an object, it will autorelease it so you don't have to bother; typically:
- (Foo *)getFoo
{
return [[_foo retain] autorelease];
}
If you are only using foo for the lifetime of the calling method you don't need to retain it, as it won't be autoreleased until next time through the run loop, so your code should actually be:
Foo *foo = [bar getFoo]; //In my bar method I return foo
[foo callMethod];
If, however, you want to hold foo for a while, outside the scope of the calling method, you need to retain it and then release it sometime later.
One more thing; the convention for getter method names is simply "name", so your setter should be setFoo and your getter would be foo. Keeping to the naming conventions is a good idea as it lets you know what a method does, in say 7 months time, and tools like static analysis understand the conventions.
The method getFoo doesn't return an object with a 0 retain count. It returns an object with a +0 retain count which means that:
the object's retain count is not null (otherwise, the object wouldn't exist)
and the retain count wasn't altered by the invocation of the method, or if it was, it was in a balanced way (with as many release/autorelease as retain/alloc/new/copy).
Thus the lifetime of the object entirely depends on where and how it is retained. We don't know how long the object will be valid as any method invocation could release the object.
For example, let's consider the following code:
id anObject = [anArray objectAtIndex:0];
[anArray removeObjectAtIndex:0];
The object anObject isn't retained any more by the array as we removed it. Therefore it may have been destructed (but maybe it wasn't because it is still used somewhere else).
Generally, when getting an object from a method (other that alloc, copy, new or retain), we can assume that:
either the object was retained then autoreleased,
either the object is retained by the object that returned it.
So we know the object foo is valid until we return from the current method/function or we invoke a method/function that alter the state of the object bar, whichever comes first. After that, it may have been destructed.
So in your case, you can safely omit the retain/release pair.
However, it is very difficult to guaranty that an object doesn't get released unless we know the implementation of every method we invoke. Therefore, retaining (then releasing) every single object we get is the safer approach and that's what the compiler will do when you enable ARC (Automatic Reference Counting).
But that would require you to write a lot of retain/release and your code would become difficult to read, understand and maintain. Moreover, the more code you write, the more bugs you get (unless you never write bugs).
In conclusion, you don't need to retain an object unless you have a reason to suspect it could vanish otherwise.
I'm having a hard time understanding copyWithZone.
I know it's supposed to return a copy, but if I add an object to a dictionary, it adds a 'copyWithZone' object to the dictionary. If I make an actual copy (that is, a new object), then the object added to the dictionary will not be the same object. However, if I only increase the retain count, then it's not technically a copy.
Should I just retain self, or make an actual copy?
copyWithZone: is supposed to return an immutable object (if there are immutable and mutable versions of the class). If the original is immutable, simply retaining & returning the original would be safe, since none of the owners could mutate the object. Otherwise (i.e. original is mutable or the immutable/mutable dichotomy doesn't apply), return a copy.
As for NSDictionary and NSMutableDictionary, generally only the keys are copied (items are only copied if you explicitly say to with -initWithDictionary:copyItems:), which is necessary as the internal data structure of the dictionary depends on the key values. If you were to mutate a key being used by a dictionary, it would corrupt the dictionary's data structure and you would no longer be able to retrieve the item for that key, or worse.
I'm learning how to program, and starting off with Objective C. I'm trying to understand exactly what happens when an object is allocated from within a method.
-(Fraction *) add: (Fraction *) f
{ //'result' will store the result of the addition
Fraction *result = [[Fraction alloc]init];
result.numerator = (numerator*f.denominator + denominator*f.numerator);
result.denominator = denominator*f.denominator;
[result reduce];
return result;
}
I understand that I can create an object to store 'result' in when it is returned,
tempStorageObject = [aFraction add: bFraction];
and that i am then responsible for releasing it, but what happens when I don't store it, as in:
[aFraction add: bFraction];
NSLog(#"%i/%i", result.numerator, result.denominator); //result object not declared in main
I am told that I have an undeclared identifier. I get that, but what exactly happens to 'result' after using my 'add' method. Where does it go? Shouldn't I be able to access its variables since it was created and returned in the method? Obviously not, but I'm not clear on why. I've tried re-reading my book and searching this forum but I can't find a clear answer. Thanks. (First post)
Four different things:
Properties
Local variables
Function return values
Heap storage
"I get that, but what exactly happens to 'result' after using my 'add' method. Where does it go?"
It's a local variable. It's gone.
"Shouldn't I be able to access its variables"
Seeing your comment, it looks like you mean access by dot notation. No, dot notation is for properties.
"since it was created"
Dot notation does not give you access to local variables.
"and returned in the method?"
Dot notation does not give you access to function return values.
All of the first three things are pointers, when they refer to objects. The fourth thing is what they point to. When you do alloc, you create an object in heap storage. You then have instance variables, properties, local variables, and function return values refer to the heap storage. In a way you think of them as being the same thing as the object in heap storage. Syntactic sugar like dot notation helps you do that. Your object will last, but in this case the different variables that refer to it are limited in scope and come and go.
When you call alloc, an object is created on the heap.
When you assign it to result, result now has the same object.
When you return result, the local variable result no longer exists, the return value temporarily holds the same object, and the object still exists in the heap.
4a. When you assign the function result to tempStorageObject, another local variable (I guess), the function result goes away. It existed only temporarily to pass a value from inside the function to out. tempStorageObject now holds the object, and the object still exists in the heap.
4b. Instead if you don't assign the function result to anything, then the function result still goes away. But the object still exists on the heap. You have a problem. You have an object on the heap, but you can't refer to it directly there (unless you are good at guessing its address). Without being able to refer to it, you can't get it off the heap, which will be a major problem if you do that kind of thing over and over. The heap will start to get full with objects you can't get rid of and you'll run out of memory. That's what's called a leak.
The correct thing to do in this case is to return [result autorelease]. When you call [something autorelease], it adds "something" to an "autorelease pool" and then returns the same something.
You call alloc and create an object on the heap. Its retain count starts at 1.
You assign it to result, a local variable. Result has the object and it's on the heap.
[result autorelease]. result has the object, it's in an autorelease pool, and it's on the heap.
return that. result is gone, the return value has the object, it's in the autorelease pool, and it's on the heap.
5a. Assign the return value to tempStorageObject. The return value is gone, tempStorageObject has the object, it's in an autorelease pool, and it's on the heap.
6a. You leave the scope of tempStorageObject. tempStorage object is gone. The object is in an autorelease pool and on the heap.
5b. You don't assign the function result to anything. The function result is gone. The object is in an autorelease pool and on the heap.
7ab. The autorelease pool is drained. That is usually done from code in the main run loop provided by the system library, but you can do it yourself if you know how. All the objects in the autorelease pool, including the one we're paying attention to, are sent a release message. The object's retain count goes to 0.
8ab. With a retain count of 0, the object is removed from the heap. The object is in the autorelease pool.
9ab. The second thing drain does is remove all the objects from the pool. Now the object doesn't exist anywhere anymore.
You said you are familiar with release, so I just say you should use autorelease keyword, which releases the allocated object when no more code blocks need it, check document below, from Apple:
Memory Management Programming
The scope of alloc is global: once you have allocated an object, there is room for it in memory and that memory will remain allocated until the release count hits zero (or the app is terminated). Until then, the object will still exist.
The scope of a variable is much shorter. In your example 'result' goes out of scope right at the end of the method 'add'. But that variable is just a name, a reference to an object. So whoever is calling add, should make sure to do something with the returned object. Otherwise there is no more variable referring to the object and so it can not be released.
Isn't it unnecessary to retain a static variable since it stays around for the duration of the program, no matter if you release it?
See this code:
https://github.com/magicalpanda/MagicalRecord/blob/master/Source/Categories/NSManagedObjectContext+MagicalRecord.m#L24-29
I'm assuming you mean a static object pointer, such as static NSString *foobar;.
Such variables indeed have a lifetime as long as the application, but the variables we're talking about are pointers only. In Objective-C, objects are always dynamically allocated, and so we always address them with a pointer to their type, but the underlying data for an object is still present out in the dynamically allocated wild blue yonder.
You must still retain the object because, while the pointer to the object will never go out of scope, the object itself can be deallocated just like any other object, and so your pointer will end up pointing to garbage, or worse, another unrelated object.
A simplified version of Jonathan Grynspan's accepted answer:
The retain isn't for the variable which points to an object. That variable will last forever because it's static. The retain is for the object the variable points to. Without the retain the object could (and should) be deallocated. Then you've got a variable pointing to a thing which will cause a sigabrt. This variable pointing nowhere is known as a "dangling pointer."
For the ARC context, the best thing to do is declare the static variable as strong, so something like this:
static ThatClass * __strong thatStaticVariable;
This ensures that the object that thatStaticVariable points to will be a valid object (i.e., never gets deallocated) once assigned. However, you don't actually need the __strong keyword at all, because it's the default (so sayeth the docs, thanks to #zpasternack), so just use
static ThatClass *thatStaticVariable;
and you're good.
Note: forever = while the application is running