[英]Why does std::copy_n not increment the Input iterator n times?
我希望以下內容讓buf_iter
指向它開始的點之后的字符n
字符。 相反,它指向最后一個字符讀取。 為什么是這樣? 即如果我在copy_n之前和之后進行in_stream.tellg(),它們的區別不是n
而是(n-1)
。 如果我用in_stream.read
讀取n
字符,那么該位置將被n
提前。
std::istreambuf_iterator<char> buf_iter(in_stream);
std::copy_n(buf_iter, n, sym.begin());
我已經查看了實現,它顯然是故意這樣做的,跳過最后的增量。
這里的另一篇文章提到,當它連接到cin
,從迭代器遞增會導致讀取太多,因為讀取是在operator++()
。 這聽起來像是cin
的問題 - 為什么不在operator*()
上完成讀取?
標准是否在任何地方指定了它? 我見過的文檔沒有提到from迭代器會發生什么,我看到兩個不同的頁面提供了“可能正確的實現”,它們執行每個行為:
template< class InputIt, class Size, class OutputIt>
OutputIt copy_n(InputIt first, Size count, OutputIt result)
{
if (count > 0) {
*result++ = *first;
for (Size i = 1; i < count; ++i) {
*result++ = *++first;
}
}
return result;
}
template<class InputIterator, class Size, class OutputIterator>
OutputIterator copy_n (InputIterator first, Size n, OutputIterator result)
{
while (n>0) {
*result = *first;
++result; ++first;
--n;
}
return result;
}
兩者都讀取並導致結果中的相同內容。 但是,第一個只會增加“第一個”迭代器n-1
次,第二個將增加n
次。
是什么賦予了? 我如何編寫可移植代碼? 我可以使用tellg
然后seekg
但然后我也可以手動執行循環(呃!)。
請注意,我並不想調用后,從迭代器讀取copy_n
,而我想打完電話后從底層流讀取copy_n
,問題是, copy_n
是左指着字節的短信,我就希望它是的。 現在我要帶着一些有點可怕但顯然便攜的東西:
auto pos = in_stream.tellg();
std::istreambuf_iterator<char> buf_iter(in_stream);
std::copy_n(buf_iter, cl, sym.begin());
in_stream.seekg(pos + cl);
uint64_t foo;
in_stream.read(reinterpret_cast<char *>(&foo), 8);
順便說一句,如果不清楚,我試圖避免將數據復制到緩沖區然后再次進入字符串sym
。
@DaveS:擺脫我的具體問題,這是一個簡單的程序,由於輸入迭代器在最后時間沒有增加這一事實,因此無法輸出我期望的結果:
#include <algorithm>
#include <string>
#include <iostream>
#include <fstream>
int main(int argc, const char * argv[])
{
std::ifstream in("numbers.txt");
std::istreambuf_iterator<char> in_iter(in);
std::ostreambuf_iterator<char> out_iter(std::cout);
std::copy_n(in_iter, 3, out_iter);
std::cout << std::endl;
std::copy_n(in_iter, 3, out_iter);
std::cout << std::endl;
std::copy_n(in_iter, 3, out_iter);
std::cout << std::endl;
return 0;
}
輸入文件只是"0123456789\\n"
我越來越:
012
234
456
由於istreambuf_iterator::operator++()
的副作用,如果實現copy_n
以增加輸入迭代器n
次,則會產生不同的結果。
@aschepler:需要捕獲本地參數,但我會用它:
std::generate_n(sym.begin(), cl, [&in_stream](){ return in_stream.get(); });
n3797 [algorithms.general] / 12
在算法的描述中,運算符
+
和-
用於某些迭代器類別,而不必定義它們。 在這些情況下,a+n
的語義與a+n
的語義相同X tmp = a; advance(tmp, n); return tmp;
ba
的相同return distance(a, b);
[alg.modifying.operations]
template<class InputIterator, class Size, class OutputIterator> OutputIterator copy_n(InputIterator first, Size n, OutputIterator result);
5 效果:對於每個非負整數i <n ,執行
*(result + i) = *(first + i)
。6 返回:
result + n
。7 復雜性:完全是
n
任務。
我不確定它是否適用於InputIterators(沒有多通道),因為它不會修改原始迭代器,但總是會推進原始迭代器的副本。 它似乎也沒有效率。
[input.iterators] /表107 - 輸入迭代器要求(除迭代器外)
表達式:
++r
返回類型:X&
pre:r
是dereferencable。
post:r
是dereferenceable或r
是past-the-end。
post:r
的先前值的任何副本不再需要可解除引用或在==
的域中。
據我所見, a
in
X tmp = a; advance(tmp, n); return tmp;
因此不再需要增量。
相關缺陷報告: LWG 2173
許多std::copy_n
實現增加n-1次的原因是由於與istream_iterator
的交互,以及通常如何實現。
例如,如果您有一個包含整數的輸入文件
std::vector<int> buffer(2);
std::istream_iterator<int> itr(stream); // Assume that stream is an ifstream of the file
std::copy_n(itr, 2, buffer.begin());
因為istream_iterator
被指定為以遞增方式讀取(並且在構造或第一次取消引用時),如果std::copy_n
將輸入迭代器遞增2次,則實際上將讀取文件中的3個值。 當copy_n
的局部迭代器超出范圍時,將丟棄第三個值。
istreambuf_iterator
沒有相同的交互,因為它實際上並不像大多數istream_iterators
那樣將流中的值復制到本地副本中,但copy_n
仍然以這種方式運行。
編輯:如果copy-N增加N次(cplusplus.com描述,似乎不正確),則丟失數據的示例。 注意,這實際上僅適用於istream_iterators
或其他迭代器,它們在增量時讀取和刪除其基礎數據。
std::istream_iterator<int> itr(stream); // Reads 1st value
while(n > 0) // N = 2 loop start
{
*result = *first;
++result; ++first; // Reads 2nd value
--n; // N: 1
// N = 1 loop start
*result = *first;
++result; ++first; // Reads 3rd value
--n; // N :0
// Loop exit
}
return result;
源迭代器不是通過引用獲取的。 因此,它的副本增加n次,但參數保持不變。
10次中有9次,這就是你想要的。
關於具體增加InputIterators的副作用,我認為正式,輸入迭代器應該在每次讀取時“遞增”(沒有增量的重復讀取不會產生相同的值)。 所以,只需將增量設為無操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.