Memory
Ownership
An ownership convention decides which function is responsible for freeing heap storage.
owner
The owner of a heap pointer is responsible for calling `free`.
transfer
Passing a pointer to a consuming function can transfer that responsibility.
Ownership
ownership.c
Replay: real traced execution (multi-file project)
#include <stdio.h>
#include <stdlib.h>
int *makeValue(int value) {
int *ptr = (int *)malloc(sizeof(int));
if (ptr != 0) {
*ptr = value;
}
return ptr;
}
int consumeValue(int *owned) {
int result = *owned;
free(owned);
return result;
}
int main(void) {
int value = 6;
int *owned = makeValue(value);
if (owned == 0) {
return 1;
}
int result = consumeValue(owned);
owned = 0;
printf("result=%d owned=%d\n", result, owned == 0);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int *makeValue(int value) {
int *ptr = (int *)malloc(sizeof(int));
if (ptr != 0) {
*ptr = value;
}
return ptr;
}
int consumeValue(int *owned) {
int result = *owned;
free(owned);
return result;
}
int main(void) {
int value = 9;
int *owned = makeValue(value);
if (owned == 0) {
return 1;
}
int result = consumeValue(owned);
owned = 0;
printf("result=%d owned=%d\n", result, owned == 0);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int *makeValue(int value) {
int *ptr = (int *)malloc(sizeof(int));
if (ptr != 0) {
*ptr = value;
}
return ptr;
}
int consumeValue(int *owned) {
int result = *owned;
free(owned);
return result;
}
int main(void) {
int value = 12;
int *owned = makeValue(value);
if (owned == 0) {
return 1;
}
int result = consumeValue(owned);
owned = 0;
printf("result=%d owned=%d\n", result, owned == 0);
return 0;
}
value ← 6
18int main(void) {19 int value→ 6 = 6; //@value=9, 1220 int *owned = makeValue(value6);ptr ← ⟨addr A⟩
4int *makeValue(int value6) {5 int *ptr→ ⟨addr A⟩ = (int *)malloc(sizeof(int));6 if (ptr != 0) {if (ptr != 0)
5int *ptr = (int *)malloc(sizeof(int));6if (ptr⟨addr A⟩ != 0) {7 *ptr⟨addr A⟩ = value6;8}return ptr;
8 }9 return ptr⟨addr A⟩;10}owned ← ⟨addr A⟩
19int value = 6; //@value=9, 1220int *owned→ ⟨addr A⟩ = makeValue(value6);2122if (owned == 0) {23 return 1;24}2526int result = consumeValue(owned⟨addr A⟩);27owned = 0;result ← 6
12int consumeValue(int *owned⟨addr A⟩) {13 int result→ 6 = *owned⟨addr A⟩;14 free(owned⟨addr A⟩);15 return result6;16}result ← 6, owned ← 0
26 int result→ 6 = consumeValue(owned⟨addr A⟩);27 owned→ 0 = 0;2829 printf("result=%d owned=%d\n", result6, owned0 == 0);30 return 0;31}outputresult=6 owned=1
value ← 9
18int main(void) {19 int value→ 9 = 9;20 int *owned = makeValue(value9);ptr ← ⟨addr A⟩
4int *makeValue(int value9) {5 int *ptr→ ⟨addr A⟩ = (int *)malloc(sizeof(int));6 if (ptr != 0) {if (ptr != 0)
5int *ptr = (int *)malloc(sizeof(int));6if (ptr⟨addr A⟩ != 0) {7 *ptr⟨addr A⟩ = value9;8}return ptr;
8 }9 return ptr⟨addr A⟩;10}owned ← ⟨addr A⟩
19int value = 9;20int *owned→ ⟨addr A⟩ = makeValue(value9);2122if (owned == 0) {23 return 1;24}2526int result = consumeValue(owned⟨addr A⟩);27owned = 0;result ← 9
12int consumeValue(int *owned⟨addr A⟩) {13 int result→ 9 = *owned⟨addr A⟩;14 free(owned⟨addr A⟩);15 return result9;16}result ← 9, owned ← 0
26 int result→ 9 = consumeValue(owned⟨addr A⟩);27 owned→ 0 = 0;2829 printf("result=%d owned=%d\n", result9, owned0 == 0);30 return 0;31}outputresult=9 owned=1
value ← 12
18int main(void) {19 int value→ 12 = 12;20 int *owned = makeValue(value12);ptr ← ⟨addr A⟩
4int *makeValue(int value12) {5 int *ptr→ ⟨addr A⟩ = (int *)malloc(sizeof(int));6 if (ptr != 0) {if (ptr != 0)
5int *ptr = (int *)malloc(sizeof(int));6if (ptr⟨addr A⟩ != 0) {7 *ptr⟨addr A⟩ = value12;8}return ptr;
8 }9 return ptr⟨addr A⟩;10}owned ← ⟨addr A⟩
19int value = 12;20int *owned→ ⟨addr A⟩ = makeValue(value12);2122if (owned == 0) {23 return 1;24}2526int result = consumeValue(owned⟨addr A⟩);27owned = 0;result ← 12
12int consumeValue(int *owned⟨addr A⟩) {13 int result→ 12 = *owned⟨addr A⟩;14 free(owned⟨addr A⟩);15 return result12;16}result ← 12, owned ← 0
26 int result→ 12 = consumeValue(owned⟨addr A⟩);27 owned→ 0 = 0;2829 printf("result=%d owned=%d\n", result12, owned0 == 0);30 return 0;31}outputresult=12 owned=1
Follow the Owner
valuestarts at6.makeValue(value)allocates oneinton the heap and stores6.ownedpoints at that heap value, somainis responsible for it.consumeValue(owned)reads6, callsfree(owned), and returns6.mainsetsowned = 0, so the final print isresult=6 owned=1. | value | heap value made | function that frees it | result | owned == 0 | | ---: | ---: | --- | ---: | ---: | | 6 | 6 | consumeValue | 6 | 1 | | 9 | 9 | consumeValue | 9 | 1 | | 12 | 12 | consumeValue | 12 | 1 |
Exercise: ownership.c
Reproduce result=6 owned=1, then use values 9 and 12 to predict result=9 owned=1 and result=12 owned=1.