초기화 리스트를 사용하려면 <initializer_list> 헤더를 포함해야 한다.
#include <initializer_list>
#include <algorithm>
class vector{
...
vector(std::initializer_list<double> values)
: my_size(values.size()), data(new double[my_size])
{
std::copy(std::begin(values), std::end(values), std::begin(data));
}
vector& operator=(std::initializer_list<double> values)
{
assert(my_size == values.size());
std::copy(std::begin(values), std::end*(values), std::begin(data));
return *this;
}
}
복사하는 양이 많은 경우 얕은 복사(Shallow Copy)를 사용한다. 또한 일번작으로 깊은 복사(Deep Copy)도 제공하고 있다.
class vector{
...
vector(vector&& v)
: my_size(v.my_size), data(v.data)
{
v.data = 0;
v.my_size = 0;
}
};
이동 생성자는 원본에서 데이터를 훔쳐 빈 상태로 둔다. 여기서 vector&& v
와 같은 Rvalue 레퍼런스는 이름이 있는 Lvalue다.
C++11에서는 두 개의 앰퍼샌드 &&로 표시된 Rvalue 래퍼런스를 도입한다. 이름값이 있는 Lvalue는 Rvalue 레퍼런스로 전달할 수 없다.
Rvalue로 함수에 전달한 개체는 함수로 반환한 뒤 만료되었다고 간주한다.
class vector {
...
vector& operator=(vector&& src)
{
assert(my_size == 0 || my_size == src.my_size);
std::swap(data, src.data);
}
};
이렇게 하면 원본 src
를 파괴했을 때 해체 작업을 수행하므로 기존 데이터를 해제하지 않아도 된다.
위 두 함수는 생각보다 자주 호출되지 않는다. 그 이유는 최신 컴파일러가 데이터를 훔치는 것 보다 더 나은 최적화를 제공하기 때문이다.
inline vector ones(int n) {
vector v(n);
for (unsigned i=0; i<n; ++i)
v[i] = 1.0;
return v;
}
...
vector w(ones(7));
위 코드에서 컴파일러는 v를 생성하고 함수 끝에서 w로 복사하는 대신 w를 즉시 생성하고 그곳에서 모든 연산을 수행한다.