Почему внутренние элементы вектора копируются, когда вектор передается по значению?
#include<vector>
using namespace std;
// this func won't modify v[2].
// Meaning v[2] (and the whole inner array) was copied
// when v is passed to the func?
void modify(vector<int> v) {
v[2] = 100;
}
// this func modify v[2]
void modify(vector<int>& v) {
v[2] = 100;
}
int main() {
vector<int> v = {1,2,3,4,5,6};
// still same
modify(v);
// modified
modified2(v);
}
Я нахожу странным, что фактическое содержимое вектора копируется, когда вектор передаетсязначение.Я представляю, что реализация std :: vector должна иметь поле указателя, которое отображается на адрес в куче, где расположен фактический массив.Поэтому, когда передается вектор, даже по значению, адрес должен оставаться прежним, указывая на тот же контент.Примерно так:
#include<iostream>
using namespace std;
// a dummy wrapper of an array
// trying to mock vector<int>
class vector_int {
public:
int* inner_array; // the actual array
vector_int(int *a) {
inner_array = a;
}
int* at(int pos) {
return inner_array+pos;
}
};
// this passes the "mocked vector" by value
// but 'inner_array' is not copied
void modify(vector_int v) {
*(v.at(2)) = 10;
}
int main() {
int* a = new int[3] {1,2,3};
vector_int v = vector_int(a);
modify(v); // v[2] is modified
}
Верно ли это предположение о реализации std :: vector?Что делает векторное содержимое копируемым при передаче по значению?
EDIT
Благодаря ответу alter igel и комментарию UnholySheep я выяснил причину, по которой std :: vector имеет значение sementics (или почему был скопирован внутренний массив).
Если класс конструктора копирования явно определен в определении класса, конструктор копирования будет определять способ копирования экземпляра структуры / класса при передаче переменной в вызове функции .Таким образом, я могу определить конструктор копирования для моего vector_int
, в который я копирую весь inner_array
, например
#include<iostream>
using namespace std;
class vector_int {
public:
int* inner_array;
int len;
vector_int(int *a, int len) {
inner_array = a;
this->len = len;
}
int* at(int pos) {
return inner_array+pos;
}
// this is the copy constructor
vector_int(const vector_int &v2) {
inner_array = new int;
for (int i =0; i < v2.len; i++) {
*(inner_array+i) = *(v2.inner_array+i);
}
}
};
// Yay, the vector_int's inner_array is copied
// when this function is called
// and no modification of the original vector is done
void modify(vector_int v) {
*(v.at(2)) = 10;
}
int main() {
int* a = new int[3] {1,2,3};
vector_int v = vector_int(a,3);
//
modify(v);
}
Я проверил исходный код реализации stdlib на моем локальном компьютере (g ++ Apple LLVMверсия 10.0.0).Std :: vector определяет конструктор копирования, который выглядит следующим образом:
template <class _Tp, class _Allocator>
vector<_Tp, _Allocator>::vector(const vector& __x)
: __base(__alloc_traits::select_on_container_copy_construction(__x.__alloc()))
{
size_type __n = __x.size();
if (__n > 0)
{
allocate(__n);
__construct_at_end(__x.__begin_, __x.__end_, __n);
}
}
, который выглядит так, как будто он выполняет malloc для фактического скопированного массива + копирует массив.