mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-07 14:24:43 +00:00
revert langref section "common errdefer slip ups"
This does not belong in the language reference.
reverts 91a88a789f
This commit is contained in:
parent
11bf2d92de
commit
3ce6de8765
5 changed files with 0 additions and 178 deletions
|
|
@ -3052,32 +3052,6 @@ fn createFoo(param: i32) !Foo {
|
||||||
The {#syntax#}errdefer{#endsyntax#} statement can optionally capture the error:
|
The {#syntax#}errdefer{#endsyntax#} statement can optionally capture the error:
|
||||||
</p>
|
</p>
|
||||||
{#code|test_errdefer_capture.zig#}
|
{#code|test_errdefer_capture.zig#}
|
||||||
{#header_close#}
|
|
||||||
{#header_open|Common errdefer Slip-Ups#}
|
|
||||||
<p>
|
|
||||||
It should be noted that {#syntax#}errdefer{#endsyntax#} statements only last until the end of the block
|
|
||||||
they are written in, and therefore are not run if an error is returned outside of that block:
|
|
||||||
</p>
|
|
||||||
{#code|test_errdefer_slip_ups.zig#}
|
|
||||||
|
|
||||||
<p>
|
|
||||||
To ensure that {#syntax#}deallocateFoo{#endsyntax#} is properly called
|
|
||||||
when returning an error, you must add an {#syntax#}errdefer{#endsyntax#} outside of the block:
|
|
||||||
</p>
|
|
||||||
{#code|test_errdefer_block.zig#}
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The fact that errdefers only last for the block they are declared in is
|
|
||||||
especially important when using loops:
|
|
||||||
</p>
|
|
||||||
{#code|test_errdefer_loop_leak.zig#}
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Special care must be taken with code that allocates in a loop
|
|
||||||
to make sure that no memory is leaked when returning an error:
|
|
||||||
</p>
|
|
||||||
{#code|test_errdefer_loop.zig#}
|
|
||||||
|
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
<p>
|
<p>
|
||||||
A couple of other tidbits about error handling:
|
A couple of other tidbits about error handling:
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const Foo = struct {
|
|
||||||
data: u32,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn tryToAllocateFoo(allocator: Allocator) !*Foo {
|
|
||||||
return allocator.create(Foo);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deallocateFoo(allocator: Allocator, foo: *Foo) void {
|
|
||||||
allocator.destroy(foo);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getFooData() !u32 {
|
|
||||||
return 666;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn createFoo(allocator: Allocator, param: i32) !*Foo {
|
|
||||||
const foo = getFoo: {
|
|
||||||
var foo = try tryToAllocateFoo(allocator);
|
|
||||||
errdefer deallocateFoo(allocator, foo);
|
|
||||||
|
|
||||||
foo.data = try getFooData();
|
|
||||||
|
|
||||||
break :getFoo foo;
|
|
||||||
};
|
|
||||||
// This lasts for the rest of the function
|
|
||||||
errdefer deallocateFoo(allocator, foo);
|
|
||||||
|
|
||||||
// Error is now properly handled by errdefer
|
|
||||||
if (param > 1337) return error.InvalidParam;
|
|
||||||
|
|
||||||
return foo;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "createFoo" {
|
|
||||||
try std.testing.expectError(error.InvalidParam, createFoo(std.testing.allocator, 2468));
|
|
||||||
}
|
|
||||||
|
|
||||||
// test
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const Foo = struct { data: *u32 };
|
|
||||||
|
|
||||||
fn getData() !u32 {
|
|
||||||
return 666;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn genFoos(allocator: Allocator, num: usize) ![]Foo {
|
|
||||||
const foos = try allocator.alloc(Foo, num);
|
|
||||||
errdefer allocator.free(foos);
|
|
||||||
|
|
||||||
// Used to track how many foos have been initialized
|
|
||||||
// (including their data being allocated)
|
|
||||||
var num_allocated: usize = 0;
|
|
||||||
errdefer for (foos[0..num_allocated]) |foo| {
|
|
||||||
allocator.destroy(foo.data);
|
|
||||||
};
|
|
||||||
for (foos, 0..) |*foo, i| {
|
|
||||||
foo.data = try allocator.create(u32);
|
|
||||||
num_allocated += 1;
|
|
||||||
|
|
||||||
if (i >= 3) return error.TooManyFoos;
|
|
||||||
|
|
||||||
foo.data.* = try getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
return foos;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "genFoos" {
|
|
||||||
try std.testing.expectError(error.TooManyFoos, genFoos(std.testing.allocator, 5));
|
|
||||||
}
|
|
||||||
|
|
||||||
// test
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const Foo = struct { data: *u32 };
|
|
||||||
|
|
||||||
fn getData() !u32 {
|
|
||||||
return 666;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn genFoos(allocator: Allocator, num: usize) ![]Foo {
|
|
||||||
const foos = try allocator.alloc(Foo, num);
|
|
||||||
errdefer allocator.free(foos);
|
|
||||||
|
|
||||||
for (foos, 0..) |*foo, i| {
|
|
||||||
foo.data = try allocator.create(u32);
|
|
||||||
// This errdefer does not last between iterations
|
|
||||||
errdefer allocator.destroy(foo.data);
|
|
||||||
|
|
||||||
// The data for the first 3 foos will be leaked
|
|
||||||
if (i >= 3) return error.TooManyFoos;
|
|
||||||
|
|
||||||
foo.data.* = try getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
return foos;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "genFoos" {
|
|
||||||
try std.testing.expectError(error.TooManyFoos, genFoos(std.testing.allocator, 5));
|
|
||||||
}
|
|
||||||
|
|
||||||
// test_error=3 errors were logged
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const Foo = struct {
|
|
||||||
data: u32,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn tryToAllocateFoo(allocator: Allocator) !*Foo {
|
|
||||||
return allocator.create(Foo);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deallocateFoo(allocator: Allocator, foo: *Foo) void {
|
|
||||||
allocator.destroy(foo);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getFooData() !u32 {
|
|
||||||
return 666;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn createFoo(allocator: Allocator, param: i32) !*Foo {
|
|
||||||
const foo = getFoo: {
|
|
||||||
var foo = try tryToAllocateFoo(allocator);
|
|
||||||
errdefer deallocateFoo(allocator, foo); // Only lasts until the end of getFoo
|
|
||||||
|
|
||||||
// Calls deallocateFoo on error
|
|
||||||
foo.data = try getFooData();
|
|
||||||
|
|
||||||
break :getFoo foo;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Outside of the scope of the errdefer, so
|
|
||||||
// deallocateFoo will not be called here
|
|
||||||
if (param > 1337) return error.InvalidParam;
|
|
||||||
|
|
||||||
return foo;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "createFoo" {
|
|
||||||
try std.testing.expectError(error.InvalidParam, createFoo(std.testing.allocator, 2468));
|
|
||||||
}
|
|
||||||
|
|
||||||
// test_error=1 tests leaked memory
|
|
||||||
Loading…
Add table
Reference in a new issue