std::transform中的输入迭代器和输出迭代器来自同一容器是否安全?

9
这篇文章中,其中一个回答建议通过以下方式更改std::string的大小写:
std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);

我已经在Visual Studio 2010中使用过它,并且到目前为止它可以正常工作。但是它是否保证始终按标准工作?我的担心是,我可以想象出一些实现方式,在写入输出迭代器(第三个参数)时可能会使输入迭代器(参数一和参数二)无效。

因此,总结一下,上述方法是否安全可移植?


1
迭代器的使用是正确的 - 但 ::toupper 的使用不正确。 - nosid
@nosid:我在获取示例的帖子评论中看到::toupper可能是一个宏。我需要解决这个问题。 - John Fitzpatrick
1
它的意思是:如果您将toupper替换为一些函数char foobar(char),那么您的问题可以直接回答。但是,关于toupper存在许多问题。请查看https://dev59.com/w3RB5IYBdhLWcg3wEDql中的`unsigned char`。 - nosid
3个回答

12

是的,这是有保证安全的(只要操作本身不修改元素或使迭代器无效)。 来自草案n3337的[alg.transform]章节:

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 要求:操作符op和二元操作符binary_op不应使迭代器或子范围失效,也不应修改范围[first1,last1][first2,first2 + (last1 - first1)][result,result + (last1 -first1)]中的元素。

[...]

5 备注:在一元变换的情况下,result可以等于first;在二元变换的情况下,result可以等于first1first2


3
如果你看一下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;
}

看起来可能不“安全”。

然而,使用 std::transform(str.begin(), str.end(),str.begin(), ::toupper);

d_firstfirst1 指向同一位置,但它们不是同一个迭代器!

在单个语句中递增这两个迭代器没有任何问题。

另一个实现方式类似于此(来自 MingW 头文件),它是等效的,但看起来更加简洁。

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;
}

感谢John Bartholomew的编辑


这两个实现看起来对我来说是等效的。您能解释一下它们之间的操作区别吗? - John Bartholomew
我认为它是未定义的,但第一个实现并没有这样做——它在一行中递增了两个不同的变量,而不是两次递增同一个变量。 - John Bartholomew
3
只有当迭代器作为引用传递时才可以,但它们没有被这样传递。 - John Bartholomew
实际上,它们也必须从 str.begin()str.end() 作为非 const 引用返回,但事实并非如此。 - John Bartholomew
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/38669/discussion-between-john-bartholomew-and-p0w - John Bartholomew

2

是的,您可以将输入迭代器也用作输出迭代器,在修改算法上,这意味着修改将在源容器中进行(内联),而不是在其他目标容器上进行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接