
On Sat, Dec 20, 2008 at 21:22, Vladimir Batov <batov@people.net.au> wrote:
I'd argue that pointers do have value semantics.
I am not sure what to say to that.
swap(int *, int *) can only swap the pointees, not the pointers themselves.
In fact, swap(int* p1, int* p2) swaps the *pointers* because after the call p1 will have the value of p2 and p2 will have the value of p1.
I meant that as the declaration, not a call. A function with signature (int *, int *) -- the only way to pass a pointer to a function -- cannot swap the pointers, only the pointees. To swap the pointers themselves requires a function with signature (int *&, int*&), which is passing references-to-pointers, not pointers. So I consider pointers to have value semantics, and their pointees to have a kind of reference semantics.
I'd say that the fundamental property of pointers is that, in the relevant domain, there exists an injective map from set the "pointees" to the set of pointers (the "address of" operator, for plain pointers) and a surjective map from the set of pointer to the set of "pointees" (the "dereference" operator, for plain pointer). UUIDs fit that definition. If you label each, say, database record with a UUID, there's a surjective map from the UUID to the record (with something like "SELECT ... WHERE id = @id" in SQL), and an injective map from the record to the UUID (by looking at the id field in the record).
The same concept is likely to have different meanings in different areas and on different absraction levels. My interpretation of a pointer is pretty much as Wikipedia desribes it: In computer science, a pointer is a programming language data type whose value refers directly to (or "points to") another value stored elsewhere... For me UUID does not fit *that* definition.
Ok. If I change my argument to use "resource handle" (at a similar abstraction level to Iterator) instead of "pointer" (where a pointer is one kind of resource handle, as are socket handles, texture handles in OpenGL, and many other things) do you follow what I'm trying to say? This is the base of my thinking about UUIDs, so I agree, we're talking at cross purposes until I can find a way to communicate it well.
The point is that this is a *breaking* change in the standard unless you assume that value_type() == value_type() for every type that could be put in a std::vector in C++03. I can't think of any applicable type that breaks that assumption -- and presumably the committee couldn't either -- so I don't think that making UUID break it is a good idea.
I'd appreciate if you could clarify the following for me: Is value_type() == value_type() an assumption you made, or is it an assumption you know the committee made or the committee stated somewhere that was an expectation or even a requirement for not following which would be a *breaking* change? Could you please indicate any documents or parts of the Standard (I could not find anything of that kind)? And what exactly "my-style" UUID is breaking? These are honest questions. We've been using "my-style" UUID quite extensively (over a year) in our project and would like to know what exactly we are breaking.
I consider it an implied assumption by the committee, though it's not an explicit requirement of any sort. This is based on the following 4 statements, which I consider true: 1) The committee does not like to have the semantics of well-formed programs in one revision of the standard have different semantics in a later revision, and as such will only make such changes if they are unavoidable or, possibly, if they are determined to not affect any cases of consequence. 2) In C++03, resize(sz) on a vector is defined (through a default argument) to be equivalent to resize(sz, value_type()) [vector.capacity], so any added elements are copy-constructed from the single default-constructed instance, so they are all equivalent (by container element requirement on the copy constructor). 3) In n2798, the C++0x draft from the 2008-10 mailing (as well as in previous drafts n2723 and n2588), there are 1- and 2-parameter overloads for resize on a vector [vector.capacity], and resize(sz) is defined, in the case where sz > size(), to "[append] sz - size() default constructed elements to the sequence". 4) If two default-constructed instances are not equivalent, then the change to [vector.capacity] changes the semantics of a well-formed program. Since this change was made to the standard and it's a relatively minor one, my impression is that the committee believes that any value_type where default-constructed instances are not equivalent is not a case of any consequence. But there are, as you mention, basically no requirements placed on default constructors for container element types, so my conclusion hangs on the strictness of application of statement 1 by the library working group. ~ Scott