On February 2, 2016 2:25:42 AM EST, Noah
On 2/1/2016 5:47 PM, Rob Stewart wrote:
I mean, is the default initialization of std::vector to the empty state no more correct than leaving it uninitialized? Should we require programmers to explicitly set the vector state, even if they want to start off with an empty vector?
That's not what I asked you about. I asked if you provided a way to construct your types without initializing the data. I thought it was obvious that I was asking about a constructor overload taking an instance of, say, uninitialized_t as the mechanism. That is, one would create an instance from an argument named, say, "uninitialized."
Sorry, I'm confused. In this post I was responding to what Steve said. I wasn't trying to respond to your question. Although I guess they're related.
I understand, but he was replying to something you wrote in response to my uninitialized query and I hadn't replied to that previously.
And it may be my shortcoming, but it actually wasn't obvious to me that you were asking about "a constructor overload taking an instance of, say, uninitialized_t as the mechanism". Is that mechanism preferable to mechanism of having separate, compatible classes I proposed (in both the reply to Steve's post and the reply to your post)?
There are tradeoffs to those options. Consider things like no-throw new expressions and creating a lock guard that assumes ownership rather than acquiring its lock. Those use arguments to differentiate them from other uses, so there's precedent for the approach.
I haven't completely thought it through, but I might've thought that solution of having separate types might be preferable if only for convenience reasons because you wouldn't have to pass any arguments to get an uninitialized variable.
You have to remember a second name either way. Once constructed, the objects will be the same or very similar in behavior.
And, as Steve pointed out, if you choose to use a type that requires explicit initialization before use, it may help catch some bugs (in debug mode).
I see no conflict. [snip]
there may be issues other than just default initialization to consider. For example, what if we wanted an option to disable run-time range checking when converting between different (sized) integer types? Keeping the one class and adding an extra constructor for that wouldn't really work. Because you'd just be substituting one run-time check for another, right?
If you want that kind of control, then you want policy classes, which means different types in the end.
But another separate compatible class might work. And how about range checking on arithmetic operations? Is that too many options? Should we just not provide for those options?
Policies
Or is the empty state somehow intrinsically valid, but the zero value for integers is not?
Zero may be a valid value with semantics different than "not set." An empty vector doesn't have a magic value that means it's actually empty.
Just to be clear, I wasn't being sarcastic or anything. I'm just trying to think this through.
I didn't think otherwise.
So I agree that zero should not be interpreted as a "magic" value indicating "value not set". In my reply to Steve I suggested that the integer class for example, might, in debug mode, contain an extra bool member indicating whether or not the value had been explicitly set. And default initialization would set that bool to indicate that the value hadn't been explicitly set.
That's certainly possible.
What I am suggesting is that, perhaps, the std::vector people decided not to provide for uninitialized vector construction because a) they suspected that conditional initialization would be a small portion of all initializations and that the default empty state would be a fairly large portion, and/or possibly b) the compiler optimizer would deal with the redundancy in a significant portion of those conditional initializations, and/or c) the cost of the program being non-deterministic if a programming error slips by is unacceptably high.
Actually, vector would be quite dangerous to use without default initialization to establish its invariants. The same can't be said for an integer, though using the garbage value might be dangerous in some contexts.
Do you still prefer the single class with an extra constructor for "uninitialized construction" solution to the one I proposed?
It's hard to say. Adding a separate class or policy just to have the uninitialized case is heavy, but the overload may not apply to all specializations of the template. ___ Rob (Sent from my portable computation engine)