sorry if it's a silly question. I just started learning swift. I mainly use php for my daily job. Apple Store's Swift textbook uses the following example (i modified it into a shorter version) to demonstrate the usage of weak reference:
class Person {
var apartment: Apartment?;
}
class Apartment {
weak var tenant: Person?;
}
var john: Person?; john = Person();
var number73: Apartment?; number73 = Apartment();
john!.apartment = number73; number73!.tenant = john; //circular reference here
john = nil; number73 = nil; //deference from static variable names
In the above Apartment class definition, if the weak key word is removed from var tenant, it creates a strong reference cycle in the following code so that the two instances do not get disposed by GC. However, it appears to me the GC really does not need the indication of the weak reference. It is obvious that the two instances can not be linked from any variables in the current scope or from any static variables, so they are safe to be disposed.
Why dose Swift force the syntax? The only advantage I can figure out is the weak key word highlights the logic so the code is easier to read.
Swift does not use mark-and-sweep garbage collection. It uses reference counting. In reference counting it is counted how many references there are to each object: each time a new reference to an object is created the reference count is incremented, and each time a reference to the object is removed the reference count is decremented. As soon as an object has zero references, it is disposed. One of the major weaknesses of reference counting is that cyclic structured are not disposed of.
In your example, john has a reference to number73 and number73 has a reference to john. So, if the weak keyword is removed, each object has at least one reference to it, and so none of the objects will be disposed.
Weak references help to break cycles. Basically, weak references are not counted, and thus objects which have only weak references to them will be removed. In the example, since the Apartment instance only has a weak reference to the Person instance, the latter has a reference count of 0 and will be disposed. After that, also the Apartment instance has a reference count of 0 and will also be disposed.
Related
I have a class exposing through it's interface add function:
void AddObject(Object *o);
Inside the class I maintain the objects in set<shared_ptr<Object>>.
Since I will create shared_ptr from the received pointer I thought to limit the function argument to only rvalue pointers so to make sure that the user will not delete the pointer I use. And so I'll change the function declaration to:
void AddObject(Object* &&o);
so a typical use will be:
AddObject(new Object())
preventing the user to accidentally delete pointer I hold.
I don't want to to use shared_ptr in the interface because the user is not familiar with shared_ptr.
Do you think my suggestion is a good idea?
I think this is a bad idea. I'm sure there is a reason why shared_ptr c-tor that gets a raw pointer is marked explicit instead of using r-value. In my eyes, It's better to teach the users once about smart pointers or at least teach them about using make_shared/make_unique (which are safer and, in the case of make_shared, more efficient, BTW).
BTW, why shared_ptr and not unique_ptr?
Also, why set? Even if you want to make sure you hold each pointer only once and searching a vector each time doesn't look natural enough in your code, I don't see a reason to hold the pointers sorted instead of using unordered_set.
First of all, this approach will not prevent the user from deleting the pointer. Consider this example
auto obj = new Object();
AddObject(std::move(obj));
delete obj;
Secondly, the amount of steps between calling new and the creation of shared_ptr should be as few as possible. If anything happens inside AddObject before it can create a shared_ptr, the object will never get deleted.
The same applies if there are more arguments to AddObject(). If constructing those fails, you will leak memory.
void AddObject(Object* &&o, SomeOtherObject* x);
AddObject(new Object(), xx()); // if xx() throws, memory leak will occur
Ideally you would "wrap" object creating into shared_ptr construction:
void AddObject(std::shared_ptr<Object> o);
AddObject(std::make_shared<Object>());
Either of the following methods may solve your problem.
You may append more comments for AddObject to tell users that delete the pointer they added is not allowed. This is almost enough.
Or, you could also make Object inherits from a base class which has a private destructor and a method named destroyByOwner.
In swift I am getting the deinit function to print out a line saying that the object has been de initialized, but the object is still being reported as live in Instruments, allocations tool. I didn't think this was even possible. Is there a way to find out why it's not being freed? Or is there a way to find out what child objects could be holding it up?
Update: For Swift 4, see the additional note at the end.
Warning: This answer goes into some detail about the way the Swift runtime is implemented. The information here does not affect how you write code in Swift, except in some advanced scenarios. The main point is that from your point of view as a programmer, once deinit is called, the object is dead to you and you cannot use it any more.
The reason the memory is not freed is that objects in Swift are not necessarily deallocated (freed) straight away when they are deinited. Weak references to an object will cause the 'husk' of the object to stay allocated (in memory - you still can't use it!) until all the weak references have been zeroed.
Weak references in Swift are not zeroed immediately when the object is deinited, but they will be zero the next time they are accessed. That is, Swift zeroes weak references lazily. Here's an example:
public class MyClass {
}
var object = MyClass()
weak var weakObject = object
print (weakObject) // Points at a MyClass instance
object = MyClass()
// A: weakObject is not yet nil
print(weakObject) // prints 'nil'
// B: now weakObject is nil
After assigning object to a new instance (line 6), you would think that the weak reference to the original object would be zero, but it's not (yet). The object is deinited but stays allocated (in memory) until all the weak references are gone. At point A, a weak reference still exists, it's only on the next line when you try to evaluate the weak reference that Swift checks and notices that the object it references is deinited, so it zeroes the weak reference and then passes it to the print function to be printed. This mechanism needs the object's empty husk to remain allocated until all the weak references are gone. It is called a husk because all of its properties have been zeroed and released in deinit so it doesn't keep anything else alive (the amount of memory for an object is quite small, just enough to store its internal headers and members).
Why and how?
Each object has an internal weak reference count instead of a list of references that need to be zeroed. This is much quicker and less resource intensive to deinit because zeroing a list of weak references in a thread-safe way requires quite a long atomic/synchronized operation.
When the strong reference count reaches zero, deinit is called and the object enters the deallocating state. The run-time keeps the memory allocated because it needs to check the state of the object whenever a weak reference is accessed. Once all weak references have been accessed and zeroed (the weak reference count is zero), the memory will be freed and deallocation is complete.
Take a look at the implementation of swift_weakLoadStrong from the swift source code - this is the code that is inserted when a weak reference is accessed and made strong (for example to be assigned to a strong reference or passed into a function etc.). I have abbreviated it below. Look at the original code on github to see the full complexity of loading a weak reference:
if (object == nullptr) {
__atomic_store_n(&ref->Value, (uintptr_t)nullptr, __ATOMIC_RELAXED);
return nullptr;
}
if (object->refCount.isDeallocating()) {
__atomic_store_n(&ref->Value, (uintptr_t)nullptr, __ATOMIC_RELAXED);
SWIFT_RT_ENTRY_CALL(swift_unownedRelease)(object);
return nullptr;
}
auto result = swift_tryRetain(object);
__atomic_store_n(&ref->Value, ptr, __ATOMIC_RELAXED);
return result;
You can see that the object husk still exists in memory, and the mechanism that loads the weak reference (i.e. when you access it in your code) checks if it is deallocating, and if so it zeroes the weak reference, calls swift_unownedRelease to decrement the weak reference count and free the object if the count has reached zero, and returns nullptr (nil).
Swift 4 Update
Since Swift 4, weak references have an improved implementation that means the object husk no longer needs to hang around. Instead a small side-table is used and weak references actually point to that instead. The side-table contains a pointer to the real object and Swift knows to follow this pointer when accessing weak references. For a much more detailed explanation, read this great blog post from Mike Ash.
My suspicion would be that you are looking at different objects. Why do you believe that the object that called deinit is the same object that you're seeing in Instruments? Having more instances than you think you do (or just looking at the wrong one) is one of the most common causes of these kinds of confusion.
Is your deinit only the print statement, or are you doing anything else? In particular, are you doing anything that might accidentally retain you again? (I can't remember if that's well-defined behavior.)
Make dure you don't have any strong relationships with another object. Imagine the following:
class A {
var b: B
}
class B {
var a: A
}
a.b = xxx
b.a = yyy
If A holds a strong reference to B and B a strong reference to A, you create a strong reference cycle between them, and setting
a = nil
won't call deinit because it holds a strong reference to b. You either set a.b to nil, or use the weak references (weak keyword) to solve this.
check apple's documentation here for more details
I've got an map shared_ptrs
std::unordered_map<uint64_t, std::shared_ptr<Target>> map;
Is there a way to make them weak_ptrs at some point or do I
have to make something like
std::unordered_map<uint64_t,
std::pair<std::shared_ptr<Target>,
std::weak_ptr<Target>>> map;
and swap them?
Thanks in advance
As people already stated in the comments, you can not do that. A shared_ptr always owns a reference, while a weak_ptr never does. The API of the standard library is explicitly designed in a way that the type tells you whether you currently own a reference or not (and the only thing you should do to access pointees of weak_ptr objects is lock() them, and check the resulting shared_ptr for non-null-ness, so you can (even in a multi-threaded environment) be sure, that you own a reference for yourself while working with the object.
What you could possibly do is have a map of weak_ptr all along, and store a shared_ptr elsewhere as long as you want to keep the object alive. Depending on the design or purpose, the place for the shared_ptr might even be a member variable of the object.
If you use a map of pairs, I would not swap() the pair members, but start with a pair of a shared and a weak ptr referring to the same managed object, and just reset() the shared ptr if it is decided to drop the strong reference, not touching the weak_ptr at that point.
You can always use the weak_ptr or shared_ptr itself as the key in the map. So indeed:
std::map<std::weak_ptr<void>, std::string> information_map;
Would be able to associate strings with any kind of weak ptr, regardless of type. This is because std::less<void*> defines a weak total ordering over all possible pointer values according to the standard.
See also
Advanced Shared Pointer Programming Techniques
How to compare pointers?
Is it legal/proper c++0x to leave an object moved for the purpose of move-construction in a state that can only be destroyed? For instance:
class move_constructible {...};
int main()
{
move_constructible x;
move_constructible y(std::move(x));
// From now on, x can only be destroyed. Any other method will result
// in a fatal error.
}
For the record, I'm trying to wrap in a c++ class a c struct with a pointer member which is always supposed to be pointing to some allocated memory area. All the c library API relies on this assumption. But this requirement prevents to write a truly cheap move constructor, since in order for x to remain a valid object after the move it will need its own allocated memory area. I've written the destructor in such a way that it will first check for NULL pointer before calling the corresponding cleanup function from the c API, so that at least the struct can be safely destroyed after the move.
Yes, the language allows this. In fact it was one of the purposes of move semantics. It is however your responsibility to ensure that no other methods get called and/or provide proper diagnostics. Note, usually you can also use at least the assignment operator to "revive" your variable, such as in the classical example of swapping two values.
See also this question
I'm still new to Cocoa and don't know much about memory management. I read up on Apple's documentation but I'm still confused. My question is if I set the value of a variable in a - (void)dowhatever when dowhatever ends, will the contents of the variable be erased? If so is there a method (without writing to a file) that I can use to retain the variable contents?
Thanks for any help
My question is if I set the value of a variable in a - (void)dowhatever when the void ends, …
void is a type. It has no beginning and no end.
Specifically, it's the return type of the dowhatever method. If dowhatever returned a value, the type of that return value would be where you have void; it would say, for example, - (NSUInteger) doWhatever. Having void there means that the method does not return a value.
See also the Objective-C 2.0 Programming Language document.
… will the contents of the variable be erased?
If it's a local variable, then the variable will cease to exist when the method returns.
An instance variable exists as long as the instance (object) that the variable is a part of exists—that is, until the instance is deallocated.
Instance variables are also covered in the Objective-C documentation.
If so is there a method (without writing to a file) that I can use to retain the variable contents?
If you simply need to return the object to your caller, retain it and autorelease it. See the Memory Management Programming Guide for Cocoa for more info.
If that's not what you're doing, then the question becomes why you need the object to stay alive.
Think in terms of objects: An object may own certain other objects, and has an instance variable for every object it owns*. As long as you have your ownerships straight and uphold them in code, objects' lifetimes just work.
If object A needs another object B, then A should own B. This ownership isn't exclusive; it can co-own B. But it needs to at least co-own B; B will remain alive as long as it has at least one owner.
That's also covered in the Memory Management Guide. For other examples of relationships between objects, you should flip through the Cocoa Fundamentals Guide, particularly the chapter on Cocoa's design patterns, and you may want to look through sample code to see those patterns demonstrated in practice.
*It can also have instance variables for objects it doesn't own, such as delegates. You can have an instance variable for an object you don't own, but if you do own it, you should have an instance variable for it.