| author | |
| committer | |
| log | 3ce6de87657e67da358e9c7869a87c61cc9f1305 |
| tree | 6ed26d60882e80967afe849abfc172bd4ae37ed2 |
| parent | 11bf2d92de5f335d4e07358d99f26fae08493f12 |
This does not belong in the language reference.
reverts 91a88a789ffa80ebb57c77ae0fe37594276e37075 files changed, 0 insertions(+), 178 deletions(-)
doc/langref.html.in-26| ... | @@ -3052,32 +3052,6 @@ fn createFoo(param: i32) !Foo { | ... | @@ -3052,32 +3052,6 @@ fn createFoo(param: i32) !Foo { |
| 3052 | The {#syntax#}errdefer{#endsyntax#} statement can optionally capture the error: | 3052 | The {#syntax#}errdefer{#endsyntax#} statement can optionally capture the error: |
| 3053 | </p> | 3053 | </p> |
| 3054 | {#code|test_errdefer_capture.zig#} | 3054 | {#code|test_errdefer_capture.zig#} |
| 3055 | {#header_close#} | ||
| 3056 | {#header_open|Common errdefer Slip-Ups#} | ||
| 3057 | <p> | ||
| 3058 | It should be noted that {#syntax#}errdefer{#endsyntax#} statements only last until the end of the block | ||
| 3059 | they are written in, and therefore are not run if an error is returned outside of that block: | ||
| 3060 | </p> | ||
| 3061 | {#code|test_errdefer_slip_ups.zig#} | ||
| 3062 | |||
| 3063 | <p> | ||
| 3064 | To ensure that {#syntax#}deallocateFoo{#endsyntax#} is properly called | ||
| 3065 | when returning an error, you must add an {#syntax#}errdefer{#endsyntax#} outside of the block: | ||
| 3066 | </p> | ||
| 3067 | {#code|test_errdefer_block.zig#} | ||
| 3068 | |||
| 3069 | <p> | ||
| 3070 | The fact that errdefers only last for the block they are declared in is | ||
| 3071 | especially important when using loops: | ||
| 3072 | </p> | ||
| 3073 | {#code|test_errdefer_loop_leak.zig#} | ||
| 3074 | |||
| 3075 | <p> | ||
| 3076 | Special care must be taken with code that allocates in a loop | ||
| 3077 | to make sure that no memory is leaked when returning an error: | ||
| 3078 | </p> | ||
| 3079 | {#code|test_errdefer_loop.zig#} | ||
| 3080 | |||
| 3081 | {#header_close#} | 3055 | {#header_close#} |
| 3082 | <p> | 3056 | <p> |
| 3083 | A couple of other tidbits about error handling: | 3057 | A couple of other tidbits about error handling: |
doc/langref/test_errdefer_block.zig deleted-42| ... | @@ -1,42 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Allocator = std.mem.Allocator; | ||
| 3 | |||
| 4 | const Foo = struct { | ||
| 5 | data: u32, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn tryToAllocateFoo(allocator: Allocator) !*Foo { | ||
| 9 | return allocator.create(Foo); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn deallocateFoo(allocator: Allocator, foo: *Foo) void { | ||
| 13 | allocator.destroy(foo); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn getFooData() !u32 { | ||
| 17 | return 666; | ||
| 18 | } | ||
| 19 | |||
| 20 | fn createFoo(allocator: Allocator, param: i32) !*Foo { | ||
| 21 | const foo = getFoo: { | ||
| 22 | var foo = try tryToAllocateFoo(allocator); | ||
| 23 | errdefer deallocateFoo(allocator, foo); | ||
| 24 | |||
| 25 | foo.data = try getFooData(); | ||
| 26 | |||
| 27 | break :getFoo foo; | ||
| 28 | }; | ||
| 29 | // This lasts for the rest of the function | ||
| 30 | errdefer deallocateFoo(allocator, foo); | ||
| 31 | |||
| 32 | // Error is now properly handled by errdefer | ||
| 33 | if (param > 1337) return error.InvalidParam; | ||
| 34 | |||
| 35 | return foo; | ||
| 36 | } | ||
| 37 | |||
| 38 | test "createFoo" { | ||
| 39 | try std.testing.expectError(error.InvalidParam, createFoo(std.testing.allocator, 2468)); | ||
| 40 | } | ||
| 41 | |||
| 42 | // test | ||
doc/langref/test_errdefer_loop.zig deleted-36| ... | @@ -1,36 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Allocator = std.mem.Allocator; | ||
| 3 | |||
| 4 | const Foo = struct { data: *u32 }; | ||
| 5 | |||
| 6 | fn getData() !u32 { | ||
| 7 | return 666; | ||
| 8 | } | ||
| 9 | |||
| 10 | fn genFoos(allocator: Allocator, num: usize) ![]Foo { | ||
| 11 | const foos = try allocator.alloc(Foo, num); | ||
| 12 | errdefer allocator.free(foos); | ||
| 13 | |||
| 14 | // Used to track how many foos have been initialized | ||
| 15 | // (including their data being allocated) | ||
| 16 | var num_allocated: usize = 0; | ||
| 17 | errdefer for (foos[0..num_allocated]) |foo| { | ||
| 18 | allocator.destroy(foo.data); | ||
| 19 | }; | ||
| 20 | for (foos, 0..) |*foo, i| { | ||
| 21 | foo.data = try allocator.create(u32); | ||
| 22 | num_allocated += 1; | ||
| 23 | |||
| 24 | if (i >= 3) return error.TooManyFoos; | ||
| 25 | |||
| 26 | foo.data.* = try getData(); | ||
| 27 | } | ||
| 28 | |||
| 29 | return foos; | ||
| 30 | } | ||
| 31 | |||
| 32 | test "genFoos" { | ||
| 33 | try std.testing.expectError(error.TooManyFoos, genFoos(std.testing.allocator, 5)); | ||
| 34 | } | ||
| 35 | |||
| 36 | // test | ||
doc/langref/test_errdefer_loop_leak.zig deleted-32| ... | @@ -1,32 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Allocator = std.mem.Allocator; | ||
| 3 | |||
| 4 | const Foo = struct { data: *u32 }; | ||
| 5 | |||
| 6 | fn getData() !u32 { | ||
| 7 | return 666; | ||
| 8 | } | ||
| 9 | |||
| 10 | fn genFoos(allocator: Allocator, num: usize) ![]Foo { | ||
| 11 | const foos = try allocator.alloc(Foo, num); | ||
| 12 | errdefer allocator.free(foos); | ||
| 13 | |||
| 14 | for (foos, 0..) |*foo, i| { | ||
| 15 | foo.data = try allocator.create(u32); | ||
| 16 | // This errdefer does not last between iterations | ||
| 17 | errdefer allocator.destroy(foo.data); | ||
| 18 | |||
| 19 | // The data for the first 3 foos will be leaked | ||
| 20 | if (i >= 3) return error.TooManyFoos; | ||
| 21 | |||
| 22 | foo.data.* = try getData(); | ||
| 23 | } | ||
| 24 | |||
| 25 | return foos; | ||
| 26 | } | ||
| 27 | |||
| 28 | test "genFoos" { | ||
| 29 | try std.testing.expectError(error.TooManyFoos, genFoos(std.testing.allocator, 5)); | ||
| 30 | } | ||
| 31 | |||
| 32 | // test_error=3 errors were logged | ||
doc/langref/test_errdefer_slip_ups.zig deleted-42| ... | @@ -1,42 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Allocator = std.mem.Allocator; | ||
| 3 | |||
| 4 | const Foo = struct { | ||
| 5 | data: u32, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn tryToAllocateFoo(allocator: Allocator) !*Foo { | ||
| 9 | return allocator.create(Foo); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn deallocateFoo(allocator: Allocator, foo: *Foo) void { | ||
| 13 | allocator.destroy(foo); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn getFooData() !u32 { | ||
| 17 | return 666; | ||
| 18 | } | ||
| 19 | |||
| 20 | fn createFoo(allocator: Allocator, param: i32) !*Foo { | ||
| 21 | const foo = getFoo: { | ||
| 22 | var foo = try tryToAllocateFoo(allocator); | ||
| 23 | errdefer deallocateFoo(allocator, foo); // Only lasts until the end of getFoo | ||
| 24 | |||
| 25 | // Calls deallocateFoo on error | ||
| 26 | foo.data = try getFooData(); | ||
| 27 | |||
| 28 | break :getFoo foo; | ||
| 29 | }; | ||
| 30 | |||
| 31 | // Outside of the scope of the errdefer, so | ||
| 32 | // deallocateFoo will not be called here | ||
| 33 | if (param > 1337) return error.InvalidParam; | ||
| 34 | |||
| 35 | return foo; | ||
| 36 | } | ||
| 37 | |||
| 38 | test "createFoo" { | ||
| 39 | try std.testing.expectError(error.InvalidParam, createFoo(std.testing.allocator, 2468)); | ||
| 40 | } | ||
| 41 | |||
| 42 | // test_error=1 tests leaked memory | ||