--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
--
The aside of the previous thread ended (I think) with my suggestion of a new method vector::resize_default_constructed(). This method would call the default constructor just like new T; does, not the value constructor like new T() does. As these two new calls only differ for trivial types the new resize method would be safe for any type (as safe as having an array of that type at least). This thinking would of course carry over to basic_string<T> as well.The reasoning behind allowing calls to resize_default_constructed for any T is to avoid having to specialize template code using vector<T> depending on if the method is available or not for the T at hand.When it comes to the quite common use case of composing a string using several operator+() concatenations I have toyed with the idea of letting the operator+() return a helper object which refers to its lhs and rhs and only when all of the concatenations have been done and the result is somehow used as a string does the references get resolved, the total character count tallied, a suitably sized malloc block allocated and finally the characters copied into it. I have not attempted to implement such a thing, however, as I think there would be countless corner cases to take care of. One of them would be auto x = string1 + string2; where there is nothing to "drive" the actual concatenation before x is used, at which time the strings may have changed value. The suggested operator auto() in another thread would fix this particular issue, but there are probably many worse ones involving functions being called that change values of strings also partaking in the concatenation. Has anyone tried anything in this direction at home?
It sounds like what you want should be a specialized type, not built in to basic_string.
--
Except everything you propose can be implemented in terms if .reserve() + .insert()/.append(), so you do in fact have the necessary facilities. Sure, those may be difficult to use in comparison, but they have the advantage that 1. they don't break basic_string's invariants, and 2. they are already in the standard and you can use them today.
If someone can show profiling data for a real world application where any kind of conversion like this mattered, then perhaps it would make sense to consider an application where a basic_string could "capture" a buffer already allocated by a user. But this uninitialized_resize thing, IMHO, induces far too many caveats.
It seems like for most of those cases where you would see a significant perf win, you'd be better off avoiding the conversion back into basic_string in the first place.
--
but how is this supposed to work now? Suppose I want to do something as simple as:
string s;
s.reserve(BIG_ENOUGH);
char buf[BIG_ENOUGH];
sprintf(buf, "%.6f", something);
I can copy the data from buf to s using insert, or I could rewrite sprintf to stick each character in using push_back (and hope that the optimizer is really, really good), but neither of those is a real solution.
I want to be able to do:
auto orig_size = s.size();
s.resize_default_initialized(orig_size + BIG_ENOUGH); /* or whatever it's called */
s.resize(orig_size + sprintf(&s[orig_size], "%.6f", something)); /* snprintf in real code */
This avoids copying and avoids rewriting sprintf.
If someone can show profiling data for a real world application where any kind of conversion like this mattered, then perhaps it would make sense to consider an application where a basic_string could "capture" a buffer already allocated by a user. But this uninitialized_resize thing, IMHO, induces far too many caveats.
What are the caveats to having a way to resize a string or a vector such that the newly-added elements are default-initialized?
I would argue that the main reason that basic_string is useful is that it's a string type that's widely used. A lot of APIs accept basic_string as input (and, with move semantics, the ability to std::move a string into some library is a big win). You can't solve a deficiency in creating basic_strings by creating a new type.
On 18 November 2013 17:23, <aml...@gmail.com> wrote:but how is this supposed to work now? Suppose I want to do something as simple as:
string s;
s.reserve(BIG_ENOUGH);
char buf[BIG_ENOUGH];
sprintf(buf, "%.6f", something);
I can copy the data from buf to s using insert, or I could rewrite sprintf to stick each character in using push_back (and hope that the optimizer is really, really good), but neither of those is a real solution.
Or you could just use s,resize(BIG_ENOUGH) instead of s.reserve(BIG_ENOUGH). Do you have any benchmarks to show that the zero filling is a performance bottleneck?
I want to be able to do:
auto orig_size = s.size();
s.resize_default_initialized(orig_size + BIG_ENOUGH); /* or whatever it's called */
s.resize(orig_size + sprintf(&s[orig_size], "%.6f", something)); /* snprintf in real code */
This avoids copying and avoids rewriting sprintf.If you really need this level of performance (which seems doubtful if you are using sprintf), use a basic_string with a different allocator that does default initialization. Problem solved.
As long as they accept basic_string (as you allege) instead of std::string, this problem is easily solvable with a different allocator.
--
> What are the caveats to having a way to resize a string or a vector such that the newly-added elements are default-initialized?You expose garbage-init data to the user, the observation of which results in undefined behavior. And you do it in such a way that existing code, not prepared to deal with this case, can be broken.
--
> I'm sure I can come up with one. I'm equally sure that someone will tell me that my benchmark is too artificial or is otherwise irrelevant. If STL doesn't care about performance on this level, then why is reserve() there?Reserve is about optimizing memory allocations, not object initialization.
1. Your example allocates once. The intent is to avoid use cases where a string allocates 1, then allocates 2, then allocates 4, then allocates 8, then allocates 16 .... Nothing in either of your examples shows a case that reserve was intended to speed up.2. You are probably benchmarking on a platform which does lazy commit, so you actually don't pay for much of the allocation costs until you actually write to the memory in question.
3. Considering there is no legal way to get to any of the memory between size() and capacity() I can't see how this is in any way an optimization for initializing the array.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
That being said, I doubt it will work: the move constructors and move assignment operators aren't templates.
On Nov 18, 2013 5:48 PM, "Nevin Liber" <ne...@eviloverlord.com> wrote:
>
> On 18 November 2013 19:21, <aml...@gmail.com> wrote:
>>
>> That being said, I doubt it will work: the move constructors and move assignment operators aren't templates.
>
>
> Could you elaborate? Move constructors and assignment operators aren't templates pretty much by definition. I fail to see the relevancy, let alone an issue.
>
How can a fancy allocator be used to create an std::string?
> --
> Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> (847) 691-1404
>
> --
>
> ---
> You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/XIO4KbBTxl0/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
How can a fancy allocator be used to create an std::string?