5

I just figured out that in Visual Studio C++ 2010, basic_string::append (iter, iter) is, obviously, not implemented by making use of std::copy.

First question:

Now suppose I implement my own iterator type, together with an optimized overloading of std::copy for my iterator type in order to provide more efficient block-wise copying. Is there any way to get basic_string::append to make use of this optimization, apart from overloading append as well?

Is there any chance that basic_string::append (iter, iter) does not do character-wise copying?

Second question (as a starting point for my own implementation):

Is the following guaranteed to be valid?

std::string t ("JohnB");
std::string s;
s.reserve (10);
std::copy (t.begin (), t.end (), s.begin ());
s.push_back ('\0');

or should I better use a back_inserter? If I use a back_inserter -- how can I avoid character-wise copying?

JohnB
  • 13,315
  • 4
  • 38
  • 65

2 Answers2

5

The string class has its own traits class that defines the operations it can do on the characters it contains.

To copy chars, basic_string<char> will use std::char_traits<char>::copy (instead of the more general std::copy). That probably maps to the memcpy function in the standard C library.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • There's no reason that there couldn't be an overload for `std::copy(const char*,const char*,char*)` to map to `memcpy` too. – Mark Ransom Nov 26 '12 at 23:34
  • There might very well be one, but `std::string` cannot use that (directly, at least), as it has to go through the `char_traits` class. – Bo Persson Nov 26 '12 at 23:36
  • Actually, I can only see a direct reference to `traits::length()` when the `std::basic_string` class template needs to determine the length of a string pointed to by a `cT const*`, and `traits::eq()` and `traits::compare()` to compare character values. I don't see any requirement that `traits::copy()` needs to be called! – Dietmar Kühl Nov 26 '12 at 23:43
  • :-) Right, the `char_traits` defines functions needed by the `basic_string` template, but the standard doesn't say that those functions has to be used. Perhaps a slight oversight? – Bo Persson Nov 27 '12 at 00:10
2

The definition of std::basic_string<cT, ...>::append() keeps delegating a few time before it eventually arrives at the overload (21.4.6.2 [string::append] paragraph 7):

basic_string& append(const charT* s, size_type n);

At this point there is clearly none of the original iterators left. In case you wonder what happens to the input iterator you may have passed to append(), the got removed by the overload in paragraph 17 of the same paragraph which states:

Effects: Equivalent to append(basic_string(first, last)).

at some intermediate state. If the standard library is implemented the way as it is literally stated by the standard there is clearly no call to std::copy().

You wouldn't really be able to see your overloaded version of std::copy() anyway, though. What the library may do is the moral equivalent of

template <typename InIt>
std::basic_string<cT, ...>& std::basic_string<cT, ...>::append(InIt begin, InIt end) {
    if (is_forward_iterator<begin>::value) {
        this->reserve(this->size() + std::distance(begin, end));
    }
    std::copy(begin, end, back_inserter_without_capacity_check<InIt>(*this);
}

Now, the other interesting bit is: Even if this is how it implemented, it doesn't really help you with respect to std::copy()! You cannot partially specialize std::copy() (well, you can't partially specialize any function template) and the type of target iterator is not defined (in the above implementation it would be a non-capacity checking variant of std::back_inserter() if InIt is a forward iterator and otherwise it would just be the same as std::back_inserter().

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Hm, but if the implementation were `using namespace std; ...; copy (begin, end, ...)`, then I could define `copy` for my iterator class (being first and second argument) in the iterator class's namespace, and my version of `copy` would be found by ADL. I really do not think the standard implementation of delegating to `append (const char *, size_type)` is a good idea, as it necessarily involves building a character array first. – JohnB Nov 27 '12 at 14:22
  • I'm not claiming that it is a Good Idea at all. All I'm saying is that this is what the standard says and it implies that the implementation actually shall not call a vanilla, ADL-findable version of `copy()`. Also, if it found both your `copy()` specialized on the input iterators it could create an ambiguity with a version of `copy()` specialized on the output iterator. It seems more reasonable to stay out of this and not to consider `copy()` to be a customization point. – Dietmar Kühl Nov 27 '12 at 14:32