std :: copy、std :: copy_backwardおよび重複する範囲

ヴィノド

私の参照はstd :: copystd :: copy_backwardです。

template <class InputIt、class OutputIt> OutputIt copy(InputIt first、InputIt last、OutputIt d_first);

[first、last)の範囲内のすべての要素を、最初から最後までコピーします-1。d_firstが[first、last)の範囲内にある場合、動作は定義されません。この場合、代わりにstd :: copy_backwardを使用できます。

テンプレート<クラスBidirIt1、クラスBidirIt2> BidirIt2 copy_backward(BidirIt1が最初、BidirIt1が最後、BidirIt2 d_last)

[first、last)で定義された範囲から、d_lastで終わる別の範囲に要素をコピーします。要素は逆の順序でコピーされます(最後の要素が最初にコピーされます)が、それらの相対的な順序は保持されます。

d_lastが(first、last]内にある場合、動作は未定義です。その場合、std :: copy_backwardの代わりにstd :: copyを使用する必要があります。

重複する範囲をコピーする場合、左にコピーする場合はstd :: copyが適切であり(宛先範囲の先頭がソース範囲外)、右にコピーする場合はstd :: copy_backwardが適切です(宛先範囲の終わりがソース外です)。範囲)。

上記の説明から、私は次の推論を収集します。

copyとcopy_backwardはどちらも、同じソース範囲[first、last)を宛先範囲にコピーすることになります。ただし、前者の場合は最初から最後の-1までコピーが行われ、後者の場合は最後からコピーが行われます。 -1から最初。どちらの場合も、ソース範囲内の要素の相対的な順序は、結果の宛先範囲で保持されます。

ただし、次の2つの規定の背後にある技術的な理由は何ですか。

1)コピーの場合、d_firstが[first、last)の範囲内にあると、未定義の動作が発生します(ソース範囲から宛先範囲へのコピーが失敗し、システム障害が発生する可能性があります)。

2)copy_backwardの場合、d_lastが範囲(first、last]内にあると、未定義の動作が発生します(ソース範囲の宛先範囲へのコピーの失敗と、場合によってはシステム障害を意味します)。

上記の未定義の動作シナリオを回避するためにcopyをcopy_backwardに置き換えるという提案は、上記の2つのステートメントの意味を理解すると明らかになると思います。

同様に、左にコピーするときのコピーの適切性(この概念は私にはわかりません)、および右にコピーするときのcopy_backward(この概念も私にはわかりません)についての言及が始まると思います。上記のcopyとcopy_backwardの違いを理解したら、意味があります。

いつものようにあなたの役に立つ考えを楽しみにしています。

補遺

フォローアップとして、次のテストコードを記述して、同一の操作でcopyとcopy_backwardの両方の動作を検証しました。

#include <array>
#include <algorithm>
#include <cstddef>
#include <iostream>

using std::array;
using std::copy;
using std::copy_backward;
using std::size_t;
using std::cout;
using std::endl;

int main (void)
{
    const size_t sz = 4;

    array<int,sz>a1 = {0,1,2,3};
    array<int,sz>a2 = {0,1,2,3};

    cout << "Array1 before copy" << endl;
    cout << "==================" << endl;

    for(auto&& i : a1) //the type of i is int&
    {
        cout << i << endl;
    }

    copy(a1.begin(),a1.begin()+3,a1.begin()+1);

    cout << "Array1 after copy" << endl;
    cout << "=================" << endl;

    for(auto&& i : a1) //the type of i is int&
    {
        cout << i << endl;
    }

    cout << "Array2 before copy backward" << endl;
    cout << "===========================" << endl;

    for(auto&& i : a2) //the type of i is int&
    {
        cout << i << endl;
    }

    copy_backward(a2.begin(),a2.begin()+3,a2.begin()+1);

    cout << "Array2 after copy backward" << endl;
    cout << "==========================" << endl;

    for(auto&& i : a2) //the type of i is int&
    {
        cout << i << endl;
    }


    return (0);
}

プログラムの出力は次のとおりです。

Array1 before copy
==================
0
1
2
3
Array1 after copy
=================
0
0
1
2
Array2 before copy backward
===========================
0
1
2
3
Array2 after copy backward
==========================
2
1
2
3

明らかに、d_firstが[first、last)の範囲内にある場合でも、copyは期待される結果を生成しますが、copy_backwardは生成しません。さらに、d_lastも範囲(first、last]内にあるため、ドキュメントによると、copy_backwardの場合は未定義の動作になります。

したがって、実際には、プログラムの出力は、copy_backwardの場合はドキュメントに準拠していますが、copyの場合はそうではありません。

どちらの場合も、d_firstとd_lastは条件を満たしているため、ドキュメントに従って、copyとcopy_backwardの両方でそれぞれ未定義の動作が発生することに注意してください。ただし、未定義の動作は、copy_backwardの場合にのみ観察されます。

ジャミ

ここでは何も深くは起こっていません。単純なアプローチを使用して、サンプルデータでアルゴリズムのランスルーを実行するだけです。各要素を順番にコピーします。

4要素の配列がint a[4] = {0, 1, 2, 3}あり、最初の3つの要素を最後の3つの要素にコピーするとします。理想的には、で終わるでしょう{0, 0, 1, 2}これはどのように機能しstd::copy(a, a+3, a+1)ますか(機能しません)

手順1:最初の要素をコピーするa[1] = a[0];配列は次のようになり{0, 0, 2, 3}ます。

手順2: 2番目の要素をコピーするa[2] = a[1];配列は次のようになり{0, 0, 0, 3}ます。

手順3: 3番目の要素をコピーするa[3] = a[2];配列は次のようになり{0, 0, 0, 0}ます。

これらの値を読み取る前にソースデータ(a[1]およびa[2])の一部を上書きしたため、結果は間違っています逆の順序では、値を上書きする前に読み取るため、逆のコピーは機能します。

1つの合理的なアプローチでは結果が間違っているため、標準では動作が「未定義」であると宣言されています。素朴なアプローチを取りたいコンパイラーはそうかもしれません、そして彼らはこの場合を説明する必要はありません。この場合、間違っていても大丈夫です。異なるアプローチをとるコンパイラーは、異なる結果を生成する可能性があり、おそらく「正しい」結果でさえあります。それもOKです。コンパイラにとって最も簡単なものは、標準では問題ありません。


質問の補遺に照らして:これは未定義の動作であることに注意してくださいこれは、動作がプログラマーの意図に反するものとして定義されていることを意味するものではありません。むしろ、動作がC ++標準で定義されていないことを意味します。何が起こるかを決めるのは各コンパイラー次第です。の結果はstd::copy(a, a+3, a+1)何でもかまいません。の素朴な結果が得られる可能性があり{0, 0, 0, 0}ます。ただし、代わりにの意図した結果が得られる場合があり{0, 0, 1, 2}ます。他の結果も可能です。幸運にも意図した動作が得られたという理由だけで、未定義の動作がないと結論付けることはできません。未定義の動作で正しい結果が得られる場合があります。(これが、未定義の動作に関連するバグの追跡が非常に難しい理由の1つです。)

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

std.algorithm.copyおよびstd.digest

分類Dev

std :: is_copy_constructable for std :: vector

分類Dev

std :: copy_nは重複する範囲で機能しますか?

分類Dev

std :: listをstd :: copyで複製し、std :: list :: eraseで削除する

分類Dev

std :: copyおよびstd :: vector :: assignの変換警告

分類Dev

`std :: copy()`と `std :: back_inserter()`の使用

分類Dev

Create a std::vector of std::vectors of class without copy constructor

分類Dev

Returning std::function without making a copy

分類Dev

how to copy part of char buffer to std::string?

分類Dev

std :: uninitialized_copyとstd :: copyの違いは?

分類Dev

std :: forwardおよびcopyコンストラクタ

分類Dev

std :: copy_ifとstd :: transformを組み合わせる方法は?

分類Dev

同じベクターの異なる範囲の複数のスレッドからstd :: copyを呼び出すことは安全ですか?

分類Dev

std :: filesystem :: copy()とstd :: filesystem :: copy_file()の違いは何ですか?

分類Dev

std :: moveがstd :: copyのように動作するのはなぜですか?

分類Dev

Accessing unique_ptrs in std vector - must provide copy constructor?

分類Dev

int **のstd :: copyの使用方法

分類Dev

std :: copyの間違った使用?

分類Dev

std :: copyの間違った使用?

分類Dev

How do I derive Copy when using #![no_std]?

分類Dev

std :: copyからのOutputIteratorリターン

分類Dev

std :: range :: copyとアダプタを使用してstd :: mapを印刷する

分類Dev

std :: copy_nを使用してstd :: vectorの内容を出力する方法は?

分類Dev

std :: copyアルゴリズムでstd :: make_move_iteratorを使用する方法は?

分類Dev

std :: pair <char、std :: string>でstd :: copy toostreamに問題があるのはなぜですか

分類Dev

std :: copyでunique_ptrを使用する方法は?

分類Dev

Std :: copyがデバッグビルドで失敗する

分類Dev

Std :: copyおよびstd :: ostream_iteratorは、オーバーロード関数を使用して値を出力します

分類Dev

std :: vector :: emplace_backおよびstd :: move

Related 関連記事

  1. 1

    std.algorithm.copyおよびstd.digest

  2. 2

    std :: is_copy_constructable for std :: vector

  3. 3

    std :: copy_nは重複する範囲で機能しますか?

  4. 4

    std :: listをstd :: copyで複製し、std :: list :: eraseで削除する

  5. 5

    std :: copyおよびstd :: vector :: assignの変換警告

  6. 6

    `std :: copy()`と `std :: back_inserter()`の使用

  7. 7

    Create a std::vector of std::vectors of class without copy constructor

  8. 8

    Returning std::function without making a copy

  9. 9

    how to copy part of char buffer to std::string?

  10. 10

    std :: uninitialized_copyとstd :: copyの違いは?

  11. 11

    std :: forwardおよびcopyコンストラクタ

  12. 12

    std :: copy_ifとstd :: transformを組み合わせる方法は?

  13. 13

    同じベクターの異なる範囲の複数のスレッドからstd :: copyを呼び出すことは安全ですか?

  14. 14

    std :: filesystem :: copy()とstd :: filesystem :: copy_file()の違いは何ですか?

  15. 15

    std :: moveがstd :: copyのように動作するのはなぜですか?

  16. 16

    Accessing unique_ptrs in std vector - must provide copy constructor?

  17. 17

    int **のstd :: copyの使用方法

  18. 18

    std :: copyの間違った使用?

  19. 19

    std :: copyの間違った使用?

  20. 20

    How do I derive Copy when using #![no_std]?

  21. 21

    std :: copyからのOutputIteratorリターン

  22. 22

    std :: range :: copyとアダプタを使用してstd :: mapを印刷する

  23. 23

    std :: copy_nを使用してstd :: vectorの内容を出力する方法は?

  24. 24

    std :: copyアルゴリズムでstd :: make_move_iteratorを使用する方法は?

  25. 25

    std :: pair <char、std :: string>でstd :: copy toostreamに問題があるのはなぜですか

  26. 26

    std :: copyでunique_ptrを使用する方法は?

  27. 27

    Std :: copyがデバッグビルドで失敗する

  28. 28

    Std :: copyおよびstd :: ostream_iteratorは、オーバーロード関数を使用して値を出力します

  29. 29

    std :: vector :: emplace_backおよびstd :: move

ホットタグ

アーカイブ