wil*_*ell 26 c++ istream-iterator
下面的片段从中读取三个整数std::cin; 它写入两个numbers并丢弃第三个:
std::vector<int> numbers(2);
copy_n(std::istream_iterator<int>(std::cin), 2, numbers.begin());
Run Code Online (Sandbox Code Playgroud)
我希望代码能够准确地读取两个整数std::cin,但事实证明这是一个正确的,符合标准的行为.这是标准中的疏忽吗?这种行为的理由是什么?
从C++ 03标准中的24.5.1/1开始:
在构造之后,每次使用++时,迭代器都会读取并存储一个值
T.
所以在上面的代码中,在调用时,流迭代器已经读取了一个整数.从那时起,算法中迭代器的每次读取都是预读,从而产生从先前读取缓存的值.
下一个标准的最新草案n3225似乎没有任何变化(24.6.1/1).
在相关的说明中,参考istream_iterator(istream_type& s)构造函数的当前标准的24.5.1.1/2 读取
效果:初始化
in_stream为s.value可以在施工期间或第一次参考时初始化.
重点是" value 可以初始化......"而不是" 应该初始化".这听起来与24.5.1/1相矛盾,但也许这应该是一个自己的问题.
dex*_*ack 10
不幸的是,copy_n的实现者未能解释复制循环中的预读.Visual C++实现在stringstream和std :: cin上都能正常工作.我还检查了原始示例中的情况,其中istream_iterator是在行中构造的.
这是STL实现的关键代码.
template<class _InIt,
class _Diff,
class _OutIt> inline
_OutIt _Copy_n(_InIt _First, _Diff _Count,
_OutIt _Dest, input_iterator_tag)
{ // copy [_First, _First + _Count) to [_Dest, ...), arbitrary input
*_Dest = *_First; // 0 < _Count has been guaranteed
while (0 < --_Count)
*++_Dest = *++_First;
return (++_Dest);
}
Run Code Online (Sandbox Code Playgroud)
这是测试代码
#include <iostream>
#include <istream>
#include <sstream>
#include <vector>
#include <iterator>
int _tmain(int argc, _TCHAR* argv[])
{
std::stringstream ss;
ss << 1 << ' ' << 2 << ' ' << 3 << ' ' << 4 << std::endl;
ss.seekg(0);
std::vector<int> numbers(2);
std::istream_iterator<int> ii(ss);
std::cout << *ii << std::endl; // shows that read ahead happened.
std::copy_n(ii, 2, numbers.begin());
int i = 0;
ss >> i;
std::cout << numbers[0] << ' ' << numbers[1] << ' ' << i << std::endl;
std::istream_iterator<int> ii2(std::cin);
std::cout << *ii2 << std::endl; // shows that read ahead happened.
std::copy_n(ii2, 2, numbers.begin());
std::cin >> i;
std::cout << numbers[0] << ' ' << numbers[1] << ' ' << i << std::endl;
return 0;
}
/* Output
1
1 2 3
4 5 6
4
4 5 6
*/
Run Code Online (Sandbox Code Playgroud)
今天我遇到了非常相似的问题,这是示例:
#include <iostream>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <string>
struct A
{
float a[3];
unsigned short int b[6];
};
void ParseLine( const std::string & line, A & a )
{
std::stringstream ss( line );
std::copy_n( std::istream_iterator<float>( ss ), 3, a.a );
std::copy_n( std::istream_iterator<unsigned short int>( ss ), 6, a.b );
}
void PrintValues( const A & a )
{
for ( int i =0;i<3;++i)
{
std::cout<<a.a[i]<<std::endl;
}
for ( int i =0;i<6;++i)
{
std::cout<<a.b[i]<<std::endl;
}
}
int main()
{
A a;
const std::string line( "1.1 2.2 3.3 8 7 6 3 2 1" );
ParseLine( line, a );
PrintValues( a );
}
Run Code Online (Sandbox Code Playgroud)
使用 g++ 4.6.3 编译上面的示例会生成一个:
1.1 2.2 3.3 7 6 3 2 1 1
Run Code Online (Sandbox Code Playgroud)
,并用 g++ 4.7.2 编译产生另一个结果:
1.1 2.2 3.3 8 7 6 3 2 1
Run Code Online (Sandbox Code Playgroud)
c++11 标准讲述了这一点copy_n:
template<class InputIterator, class Size, class OutputIterator>
OutputIterator copy_n(InputIterator first, Size n, OutputIterator result);
Run Code Online (Sandbox Code Playgroud)
效果:对于每个非负整数 i < n,执行 *(result + i) = *(first + i)。
返回:结果+n。
复杂性:正好有 n 个作业。
正如您所看到的,没有指定迭代器到底发生了什么,这意味着它依赖于实现。
我的观点是,您的示例不应读取第三个值,这意味着这是标准中的一个小缺陷,因为他们没有指定行为。
| 归档时间: |
|
| 查看次数: |
2035 次 |
| 最近记录: |