On Thu, Jul 10, 2014 at 11:39:57AM -0700, Andrei Alexandrescu via Digitalmars-d wrote: [...] > We discussed this with Bartosz literally for weeks (him being a fan of > auto_ptr for too long, later completely converted against it and I > take credit for that :o)). With auto_ptr this was possible: > > auto_ptr<int> a(new int); > auto_ptr<int> b = a; > > It would nullify a with copy syntax. That code won't compile with > unique_ptr; you'd need an explicit move(a). > > It only got worse from there: passing into functions, member > variables...
Yep, if you pass auto_ptr into a function, it goes poof after the function returns; the original reference is gone. > MOVING WITH COPY SYNTAX DOES NOT WORK. > > It's cut and dried. [...] I independently invented my own version of auto_ptr many years ago, before auto_ptr got into the standard. Basically, the idea was to annotate pointers into two classes: "owner" (i.e., auto_ptr) and "reference" (i.e., "regular" pointer). Ownership is unique, so passing owner pointers has destructive copy semantics (it "transfers ownership" to the callee), whereas passing reference pointers simply makes a copy. The rule was that copying only works one way: you can only copy an owner pointer into a reference pointer, but never the other way around. The thought was that somebody keeps a master reference to an object, assuming ownership over it, whereas others may keep as many references to it as they want, but they cannot perform owner-specific operations (like free()). Ownership may be transferred to those who are prepared to assume the responsibility of managing the object; such transfers involve destructive copy (the original owner no longer holds the rights to the object, so to speak) -- though non-owner references to that object remain valid. Thus, passing an owner pointer into a function that expects a reference pointer simply makes a copy out of it (non-destructive), whereas passing a reference pointer where an owner is expected is illegal. (Though, of course, at the time I didn't have the means to actually enforce this, so it was merely a convention.) With this annotation, function signatures became more self-documenting: class Object { ... } // Argument is a reference pointer; function doesn't expect // ownership transfer. int computeValue(ref Object *obj); // Argument is an owner pointer; i.e., the pointer is invalid // after the function returns. The function will assume // ownership of the pointer and call free(), etc., when it's // done. void addToCache(owner Object *obj); int main(int argc, char *argv[]) { owner Object *obj = new Object; // new returns an owner pointer ref Object *ref = obj; // OK, makes a copy of the pointer obj = ref; // ILLEGAL: cannot assign owner to ref int x = computeValue(ref); // OK, function expects ref x = computeValue(obj); // OK, owner implicitly converts to ref addToCache(ref); // ILLEGAL: ref doesn't convert to owner addToCache(obj); // OK: transfers ownership of obj to function // N.B. from here on, obj is now invalid, and any // dereference is a bug until it's assigned a fresh // owner pointer. obj = new Object; // OK, create another object free(ref); // ILLEGAL: can only free owner pointers free(obj); // OK, transfers ownership to free // From here on, obj is again invalid, and any further // dereference is a bug. owner Object *obj2 = new Object; obj = obj2; // OK, transfers ownership to obj. // Now obj2 is invalid and should not be dereferenced. } One thing that my system didn't address, though, was the problem of dangling reference pointers after the corresponding owner pointers have been freed. That remains an unsolved problem within that system, and ultimately, requires some form of GC to adequately address. Destructive copy, however, is tricky business; if one is not careful, one easily ends up with invalid owner pointers in the wrong places, so I agree with the sentiment of '=' being poor notation for destructive copy. Having owner pointers implicitly convert to ref pointers, however, mostly mitigates the problem -- for the most part, pointer assignments do not involve transfer of ownership, so the usual (ref) pointer semantics with non-destructive copy apply. When manipulating owner pointers, you have to be extremely careful to begin with, so generally you'd pay more attention to how it's done -- and hopefully catch problematic assignments of owner pointers. T -- Without outlines, life would be pointless.