Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't basic_string::append (iter, iter) call std::copy?

Tags:

c++

string

copy

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?

like image 951
JohnB Avatar asked Nov 26 '12 22:11

JohnB


2 Answers

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.

like image 154
Bo Persson Avatar answered Nov 14 '22 03:11

Bo Persson


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().

like image 23
Dietmar Kühl Avatar answered Nov 14 '22 04:11

Dietmar Kühl