diff --git a/README.md b/README.md index bb7f859..0afffe4 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,11 @@ Use --- After completing the building and installation steps above, importation should -work as usual. Create a `Pigosat` object `p` and use its methods. Because of the -C-language PicoSAT component of PiGoSAT, you must explicitly free `p` when you -are done using `p`, and you will not be able to use `p` thereafter. The best -practice if you are using `p` all within one function is to use `defer`. +work as usual. Create a `Pigosat` object `p` and use its methods. Even though +PicoSAT is written in C, PiGoSAT manages memory for you using +`runtime.SetFinalizer`. (If you reset a `Pigosat` instance `p`'s finalizer, you +will have to call `p.Delete` explicitly, which is best done with `defer` right +after reseting the finalizer; most users will not need to worry about this.) Designing your model is beyond the scope of this document, but Googling "satisfiability problem", "conjunctive normal form", and "DIMACS" are good @@ -65,7 +66,6 @@ package main import "pigosat" func main() { p := pigosat.NewPigosat(0) - defer p.Delete() p.AddClauses([][]int32{{1, 2}, {-2}}) status, solution := p.Solve() // Now status should equal pigosat.Satisfiable and solution should be diff --git a/pigosat.go b/pigosat.go index 110c305..35c5107 100644 --- a/pigosat.go +++ b/pigosat.go @@ -10,6 +10,7 @@ package pigosat // #include "picosat.h" import "C" import "fmt" +import "runtime" import "sync" import "time" @@ -53,12 +54,16 @@ func NewPigosat(propagation_limit uint64) *Pigosat { if propagation_limit > 0 { C.picosat_set_propagation_limit(p, C.ulonglong(propagation_limit)) } - return &Pigosat{p: p, lock: new(sync.RWMutex)} + pgo := &Pigosat{p: p, lock: new(sync.RWMutex)} + runtime.SetFinalizer(pgo, (*Pigosat).Delete) + return pgo } -// DelPigosat must be called on every Pigosat instance before each goes out of -// scope or the program ends, or else the program will leak memory. Once -// DelPigosat has been called on an instance, it cannot be used again. +// Delete may be called when you are done using a Pigosat instance, after which +// it cannot be used again. However, you only need to call this method if the +// instance's finalizer was reset using runtime.SetFinalizer (if you're not +// sure, it's always safe to call Delete again). Most users will not need this +// method. func (p *Pigosat) Delete() { if p == nil || p.p == nil { return diff --git a/pigosat_test.go b/pigosat_test.go index 05d14fc..e80486a 100644 --- a/pigosat_test.go +++ b/pigosat_test.go @@ -139,7 +139,6 @@ func TestFormulas(t *testing.T) { p.AddClauses(ft.formula) status, solution = p.Solve() wasExpected(t, i, p, &ft, status, solution) - p.Delete() } } @@ -159,11 +158,9 @@ func TestPropLimit(t *testing.T) { t.Errorf("Propagation limit %d had no effect on formula 0", limit) } - p.Delete() continue } wasExpected(t, 0, p, &ft, status, solution) - p.Delete() } } @@ -202,7 +199,6 @@ func TestPicosatVersion(t *testing.T) { // This is the example from the README. func Example_readme() { p := NewPigosat(0) - defer p.Delete() p.AddClauses([][]int32{{1, 2}, {-2}}) fmt.Println("") fmt.Printf("# variables == %d\n", p.Variables())