C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++ STLで使えるさまざまなコピー方法 ― std::copy()、copy_n()、copy_if()、copy_backward()を徹底解説

名前のとおり、copy()系のメソッドはC++ STLでデータをコピーするために使われる関数群です。それぞれ機能や受け取る引数が異なり、いずれも<algorithm>ヘッダーファイルに含まれています。ここでは、std::copy()、std::copy_n()、std::copy_if()、std::copy_backward()の4つのメソッドについて、それぞれの特徴と使い方を詳しく見ていきましょう。

copy(start_i1, end_i1, start_i2)

このメソッドは、指定した範囲内の要素をあるイテレータから別のイテレータへコピーするために使用します。範囲には開始位置と終了位置の両方の要素が含まれます。この関数は次の3種類の引数を受け取ります。

  • Start_i1:コピー元のイテレータ(i_1とする)の先頭要素を指します。ここから、コピー先のイテレータ(i_2とする)へ要素がコピーされます。
  • End_i1:コピー元のイテレータ(i_1)の終端要素を指します。この位置までの要素がコピー先イテレータ(i_2)へコピーされます。
  • Start_i2:コピー先のイテレータ(i_2)の先頭位置を指します。

戻り値:コピー先イテレータ(i_2)のうち、実際に要素がコピーされた範囲の末尾を指すイテレータを返します。

サンプルコード

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
    //ベクターvec_1を作成
    vector<int> vec_1 = { 10, 20, 30, 40, 50 };
    //サイズ6の空ベクターを宣言
    vector<int> vec_2(6);
    //copy()関数でvec_2へコピー
    copy(vec_1.begin(), vec_1.begin()+4, vec_2.begin());
    //新しいベクターを表示
    cout<<"Elements in vector v2 copied from v1: ";
    for(int i=0; i<4; i++){
        cout<<vec_2[i] << " ";
    }
}

出力

このコードを実行すると、次のように出力されます。

Elements in vector v2 copied from v1: 10 20 30 40

この例では、vec_1の先頭から4つの要素(10、20、30、40)がvec_2の先頭へ順番にコピーされています。

copy_n(start_i1, total, start_i2)

このメソッドも、あるイテレータから別のイテレータへデータをコピーするために使用しますが、「指定した位置から合計いくつの要素をコピーするか」を明示的に指定できる点が特徴です。この関数は次の3種類の引数を受け取ります。

  • Start_i1:コピー元のイテレータ(i_1)の先頭要素を指します。ここから、コピー先のイテレータ(i_2)へ要素がコピーされます。
  • Total:start_i1で指定された位置から何個の要素をコピーするかを表します。正の整数でも負の整数でも指定できますが、負の値を渡した場合は何も処理が行われません。
  • Start_i2:コピー先のイテレータ(i_2)の先頭位置を指します。

戻り値:コピー先イテレータ(i_2)のうち、実際に要素がコピーされた範囲の末尾を指すイテレータを返します。

サンプルコード

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
    //ベクターvec_1を作成
    vector<int> vec_1 = { 10, 20, 30, 40, 50 };
    //サイズ6の空ベクターを宣言
    vector<int> vec_2(6);
    //copy_n()関数でvec_2へコピー
    copy_n(vec_1.begin(), 4, vec_2.begin());
    //新しいベクターを表示
    cout<<"Elements in vector v2 copied from v1: ";
    for(int i=0; i<4; i++){
        cout<<vec_2[i] << " ";
    }
}

出力

このコードを実行すると、次のように出力されます。

Elements in vector v2 copied from v1: 10 20 30 40

copy()との違いは、終端イテレータを指定する代わりにコピーする個数を直接渡す点です。先頭からの連続したN個の要素だけをコピーしたい場合に便利です。

copy_if(start_i1, end_i1, start_i2, 条件関数)

このメソッドは、指定した範囲に対して第4引数で定義した条件を適用し、その条件を満たす要素だけをあるイテレータから別のイテレータへコピーするために使用します。この関数は次の4種類の引数を受け取ります。

  • Start_i1:コピー元のイテレータ(i_1)の先頭要素を指します。ここから、コピー先のイテレータ(i_2)へ要素がコピーされます。
  • End_i1:コピー元のイテレータ(i_1)の終端要素を指します。この位置までの要素がコピー対象となります。
  • Start_i2:コピー先のイテレータ(i_2)の先頭位置を指します。
  • 条件関数(述語):範囲内の各要素に適用したい条件を渡します。この関数の戻り値の型はboolであり、true/falseを返します。戻り値がtrueとなった要素だけがコピー先へ書き込まれます。

戻り値:コピー先イテレータ(i_2)のうち、実際に要素がコピーされた範囲の末尾を指すイテレータを返します。

サンプルコード

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
    //ベクターvec_1を作成
    vector<int> vec_1 = { 10, 21, 30, 40, 57 };
    //サイズ6の空ベクターを宣言
    vector<int> vec_2(6);
    //copy_if()関数で偶数のみvec_2へコピー
    copy_if(vec_1.begin(), vec_1.end(), vec_2.begin(), [](int i){return i%2==0;});
    //新しいベクターを表示
    cout<<"Elements in vector v2 copied from v1: ";
    for(int i=0; i<4; i++){
        cout<<vec_2[i] << " ";
    }
}

出力

このコードを実行すると、次のように出力されます。

Elements in vector v2 copied from v1: 10 30 40 0

ラムダ式で「2で割った余りが0(=偶数)」という条件を定義しているため、vec_1の中から偶数である10、30、40だけがvec_2へコピーされます。残りのスロットには、ベクター初期化時の既定値である0がそのまま残ります。

copy_backward(start_i1, end_i1, end_i2)

このメソッドは、指定した範囲のデータを後ろ向きに(末尾側から順に)あるイテレータから別のイテレータへコピーするために使用します。具体的には、コピー先の末尾位置から逆向きに要素が書き込まれていきます。上書きによるデータ破壊を避けたい場合などに役立ちます。この関数は次の3種類の引数を受け取ります。

  • Start_i1:コピー元のイテレータ(i_1)の先頭要素を指します。ここから、コピー先のイテレータ(i_2)へ要素がコピーされます。
  • End_i1:コピー元のイテレータ(i_1)の終端要素を指します。この位置までの要素がコピー対象となります。
  • end_i2:コピー先のイテレータ(i_2)の末尾位置を指します。ここがコピー範囲の終点になります。

戻り値:コピー先イテレータ(i_2)のうち、実際に要素がコピーされた範囲の先頭を指すイテレータを返します。

サンプルコード

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
    //ベクターvec_1を作成
    vector<int> vec_1 = { 10, 21, 30, 40, 57, 67 };
    //サイズ6の空ベクターを宣言
    vector<int> vec_2(6);
    //copy_backward()関数でvec_2の後方へコピー
    copy_backward(vec_1.begin(), vec_1.begin()+4, vec_2.begin()+5);
    //新しいベクターを表示
    cout<<"Elements in vector v2 copied from v1: ";
    for(int i=0; i<vec_2.size(); i++){
        cout<<vec_2[i] << " ";
    }
}

出力

このコードを実行すると、次のように出力されます。

Elements in vector v2 copied from v1: 0 10 21 30 40 0

この例では、vec_1の先頭4要素(10、21、30、40)が、vec_2のインデックス4の位置を終点として後ろから順に配置され、結果としてvec_2のインデックス1〜4に収まっています。通常のcopy()ではコピー先の「先頭」を指定するのに対し、copy_backward()ではコピー先の「末尾」を指定する点に注意してください。

  1. STLを使ったC++のvector(ベクトル)実装プログラム

    std::vectorは、動的配列のように要素の挿入や削除に応じて自動的にサイズを変更できるコンテナで、メモリ(記憶域)の管理はコンテナ自身が行います。要素は連続したメモリ領域に配置されるため、イテレータを使ったアクセスや走査が可能です。また、先頭・中間・末尾のいずれの位置にもデータを挿入・削除できます。 使用する主な関数とその説明 v.size() : ベクトルのサイズ(現在の要素数)を返します。 v.push_back() : ベクトルの末尾に要素を挿入します。 v.pop_back() : ベクトルの末尾から要素を取り除きます。 v.capacity() : 現在ベクトルに

  2. C++ STLを使ってカスタムオブジェクトのvectorをソートする方法

    C++では、STLが提供するstd::sort関数を使うことで、カスタムオブジェクトのvector(可変長配列)を簡単に並べ替えることができます。sort関数には、引数として「first(先頭イテレータ)」「last(末尾イテレータ)」「comparator(比較用の述語関数)」を受け取るオーバーロード版があります。firstとlastにはコンテナの最初と最後の要素を指すイテレータを渡し、comparatorにはコンテナをどのようにソートするかを指示する述語関数を指定します。 サンプルコード #include<iostream> #include<algorithm>