簡體   English   中英

為什么std :: copy_n沒有遞增輸入迭代器n次?

[英]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迭代器會發生什么,我看到兩個不同的頁面提供了“可能正確的實現”,它們執行每個行為:

在cppreference我們有:

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

在cplusplus.com我們有

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM