「std::vectorをコピーする」の版間の差分

提供: C++入門
移動: 案内検索
(ページの作成:「 __TOC__ == 概要 == == 簡単にstd::vectorをコピーする方法 == std::copystd::back_inserterを使用するとより簡単に書けます。 <synta...」)
(相違点なし)

2014年1月3日 (金) 12:51時点における版

概要

簡単にstd::vectorをコピーする方法

std::copystd::back_inserterを使用するとより簡単に書けます。

#include <iostream>
#include <vector>
#include <algorithm>    // std::copy
#include <iterator>     // std::back_inserter
using namespace std;
int main(int argc, char const* argv[])
{
        vector<int> v1,v2;
        for(int i = 0;i<1024*4*100;i++) {
                v1.push_back(i);
        }
        copy(v1.begin(), v1.end(), back_inserter(v2) );
        return 0;
}

コピー時にSegmentation faultが起きる

Segmentation faultが起きるコード

#include <iostream>
#include <vector>
#include <algorithm>    // std::copy
using namespace std;
int main(int argc, char const* argv[])
{
	vector<int> v1(1024*4*100, 0),v2;	// v1に0を1024*4*100個入れる
        copy(v1.begin(), v1.end(), v2.begin());
        return 0;
}

上記のコードは、Segmentation faultを引き起こします。

% ./a.out
Segmentation fault

memmoveのあたりでこけているのかもしれません。

(gdb) backtrace
#0  0x2829b5e6 in memmove () from /lib/libc.so.7
#1  0x080492d9 in std::__copy_move<false, true,
    std::random_access_iterator_tag>::__copy_m<int> ()
#2  0x08049166 in std::__copy_move_a<false, int*, int*> ()
#3  0x08048f21 in std::__copy_move_a2<false, __gnu_cxx::__normal_iterator<int*,
    std::vector<int, std::allocator<int> > >,
    __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >
    > ()
#4  0x08048c36 in std::copy<__gnu_cxx::__normal_iterator<int*, std::vector<int,
    std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*,
    std::vector<int, std::allocator<int> > > > ()
#5  0x08048a36 in main ()

Segmentation faultの解決策 1

コピー先のオブジェクトのサイズに問題があるようなので、あらかじめ std::vector::resizeでサイズ調整をしておきます。

#include <iostream>
#include <vector>
#include <algorithm>    // std::copy
using namespace std;
int main(int argc, char const* argv[])
{
	vector<int> v1(1024*4*100, 0),v2;
        v2.resize(v1.size());
        copy(v1.begin(), v1.end(), v2.begin());
        return 0;
}

Segmentation faultの解決策 2 back_inserterを使う

std::back_inserterを使用するとより簡単に書けます。

#include <iostream>
#include <vector>
#include <algorithm>    // std::copy
#include <iterator>     // std::back_inserter
using namespace std;
int main(int argc, char const* argv[])
{
	vector<int> v1(1024*4*100, 0),v2;
        copy(v1.begin(), v1.end(), back_inserter(v2) );
        return 0;
}

std::vectorにクラスのオブジェクトを入れるときの注意点

問題のないコード

このコードは、問題になりません。

include <algorithm>    // std::copy
#include <iterator>     // std::back_inserter
using namespace std;
class C {
        public:
                C(){}
                virtual ~C(){}
};
int main(int argc, char const* argv[])
{
        vector<C> v1(20, C() ),v2;
        cout << v1.size() << endl;
        copy(v1.begin(), v1.end(), back_inserter(v2) );
        return 0;
}

コピーコンストラクタの問題でエラーになるコード

このコードは、コピーコンストラクタの問題でエラーになります。

include <algorithm>    // std::copy
#include <iterator>     // std::back_inserter
using namespace std;
class C {
        public:
                C(){}
                virtual ~C(){}
                C(C& r) {}
};
int main(int argc, char const* argv[])
{
        vector<C> v1(20, C() ),v2;
        cout << v1.size() << endl;
        copy(v1.begin(), v1.end(), back_inserter(v2) );
        return 0;
}

エラーが長すぎるので、1部分だけ切り出します。 コピーコンストラクタが指摘されています。

/usr/local/lib/gcc49/include/c++/bits/stl_construct.h:75:7: error: no matching
function for call to 'C::C(C)'
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^
/usr/local/lib/gcc49/include/c++/bits/stl_construct.h:75:7: note: candidates
are:
vector_copy_with_class1.cpp:10:3: note: C::C(C&)
   C(C& r) {}
   ^
vector_copy_with_class1.cpp:10:3: note:   no known conversion for argument 1
from 'C' to 'C&'
vector_copy_with_class1.cpp:8:3: note: C::C()
   C(){}
   ^
vector_copy_with_class1.cpp:8:3: note:   candidate expects 0 arguments, 1
provided

解決策

コピーコンストラクタの引数は、constでなければなりません。

#include <iostream>
#include <vector>
#include <algorithm>    // std::copy
#include <iterator>     // std::back_inserter
using namespace std;
class C {
        public:
                C(){}
                virtual ~C(){}
                C(const C& r) {}	// 変更点は、この引数をconstにしたこと
};
int main(int argc, char const* argv[])
{
        vector<C> v1(20, C() ),v2;
        cout << v1.size() << endl;
        copy(v1.begin(), v1.end(), back_inserter(v2) );
        return 0;
}

関連項目

std::vector
メンバ 意味
constructor vectorのコンストラクタ。vectorを初期化します。
destrctor デストラクタ
operator= operator=
reserve std::vectorのキャパシティを予約します。
capacity 割り当てられているストレージキャパシティのサイズを返します。
size サイズを返します。
resize サイズをリサイズします。
shrink_to_fit コンテナのキャパシティにフィットしたサイズまで縮小します。
push_back std::vector の最後に新しい要素を追加します。要素は、コピー、もしくは、move されます。
std::vector の最後の要素を取り除きます。コンテナのサイズが1つ小さくなります。
insert std::vector に新しい要素を追加します。vector同士を連結できます。
erase std::vector の1つの要素、または、要素のレンジを削除します。
clear std::vector の要素をすべて削除します。
empty std::vector が空であれば、trueを返し、そうでなければ、falseです。
begin std::vector の最初の要素のイテレータを返します。
front std::vector の最初の要素の参照を返します。
back std::vector の最後の要素の参照を返します。
at std::vector の n 番目の要素の参照を返します。無効な要素にアクセスしたとき、 std::out_of_range の例外を送出します。 operator[] は、境界チェックをしません。
operator[] std::vector の n 番目の要素の参照を返します。 operator[] は、境界チェックをしません。
std::vector::shrink_to_fit C++11で追加された、コンテナサイズを領域に合わせます。メモリの解放に利用します。