Is it safe for the input iterator and output iterator in std::transform to be from the same container?

杀马特。学长 韩版系。学妹 提交于 2019-12-23 07:46:41

问题


In this post one of the answers recommends changing a std::string case this way:

std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);

I've used it and it works so far in Visual Studio 2010. But is it guaranteed by the standard to always work? My concern is that I can imagine the possibility of implementations where writing to the output iterator (the third argument) could invalidate the input iterators (arguments one and two).

So, in summary, is the above method safe and portable?


回答1:


Yes, this is guaranteed to be safe (as long as operation itself doesn't modify the elements or invalidate iterators).
From chapter [alg.transform] from draft n3337:

template<class InputIterator, class OutputIterator,  
    class UnaryOperation>  
OutputIterator  
transform(InputIterator first, InputIterator last,  
    OutputIterator result, UnaryOperation op);  

template<class InputIterator1, class InputIterator2,  
    class OutputIterator, class BinaryOperation>  
OutputIterator  
transform(InputIterator1 first1, InputIterator1 last1,  
    InputIterator2 first2, OutputIterator result,  
    BinaryOperation binary_op);  

2 Requires: op and binary_op shall not invalidate iterators or subranges, or modify elements in the ranges [first1,last1], [first2,first2 + (last1 - first1)], and [result,result + (last1 -first1)].

[...]

5 Remarks: result may be equal to first in case of unary transform, or to first1 or first2 in case of binary transform.




回答2:


If you look into the first possible implementation of std::transform

template<class InputIt, class OutputIt, class UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first, 
                   UnaryOperation unary_op)
{
    while (first1 != last1) {
        *d_first++ = unary_op(*first1++);
    }
    return d_first;
}

It may appear that its not "safe".

However, with std::transform(str.begin(), str.end(),str.begin(), ::toupper);

d_first and first1 point to the same place, but they are not the same iterator !

There isn't any problem with incrementing both those iterators in a single statement.

Another implementation is some what like this (from MingW header file), which is equivalent, but looks bit cleaner

template<class InputIt, class OutputIt, class UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first, 
                   UnaryOperation unary_op)
{

  for (; first1 != last1; ++first1, ++d_first)
    *d_first = unary_op(*first1);

    return d_first;
}

Edited thanks to John Bartholomew




回答3:


Yes, you can use the input iterator as the output iterator also, on a modifying algorithm it just means the modification will be done inline (on the source container) rather than on some other destination container.



来源:https://stackoverflow.com/questions/19200528/is-it-safe-for-the-input-iterator-and-output-iterator-in-stdtransform-to-be-fr

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!