У меня есть что-то вроде следующего:
#include <vector>
#include <iostream>
template<typename T>
class Vector {
private:
std::vector<T> base;
public:
Vector(const std::vector<T> vec) {base = vec;}
T& operator[](const int& index) {return base[index];}
std::vector<T> getBase() const {return base;}
};
class BigNum : public Vector<int>
{
public:
BigNum(const std::vector<int> init) : Vector(init) {}
};
int main()
{
int arr[] = {6,3,7,6,2};
std::vector<int> v(arr, arr + sizeof(arr) / sizeof(arr[0]));
BigNum num(v);
for(auto it = num.getBase().begin(); it != num.getBase().end(); ++it)
{
std::cout << *it << " "; // What going on here??
}
std::cout << "\n";
for(int i = 0; i < 5; ++i)
{
std::cout << num.getBase()[i] << " ";
}
std::cout << "\n";
}
Выход этих двух петель:
30134336 0 7 6 2
6 3 7 6 2
Что здесь происходит? Первое число в первом цикле (30134336) изменяется каждый раз, но остальные числа одинаковы. Заранее спасибо!
std::vector<T> getBase() const {return base;}
Функция возвращает копию сохраненного vector
, поэтому вы выполняете итерацию через 2 (или другой vector
каждой итерации) полностью разных векторов, которые были уничтожены вскоре после их создания. Массивное неопределенное поведение. Измените функцию на
std::vector<T> const& getBase() const {return base;}
Я бы переписал ваши классы как
template<typename T>
class Vector {
private:
std::vector<T> base;
public:
Vector(std::vector<T> vec)
: base(std::move(vec))
{}
T& operator[](int index) {return base[index];}
T const& operator[](int index) const {return base[index];}
std::vector<T> const& getBase() const {return base;}
};
class BigNum : public Vector<int>
{
public:
BigNum(std::vector<int> init) : Vector(std::move(init)) {}
};
И с С++ 11 вы можете инициализировать вектор как
std::vector<int> v{6,3,7,6,2};
Вы вызываете UB
Поскольку auto it = num.getBase().begin()
и num.getBase().end()
- это два разных векторных итератора.
Вы можете использовать:
auto v1= num.getBase();
for(auto it = v1.begin(); it != v1.end(); ++it)
{
std::cout << *it << " ";
}
Или измените getbase()
на
std::vector<T> const& getBase() const {return base;}
num.getBase()
создает копию base
элемента Vector
.num.getBase().begin()
создает итератор для этой копии.auto it = num.getBase().begin()
, копия, созданная num.getBase()
будет уничтожена. Это аннулирует итератор. Вы можете исправить это, Vector::getBase()
как
const std::vector<T>& getBase() const { return base; }
Таким образом, num.getBase()
вернет ссылку на исходную Vector::base
, insterad копии. Вам также нужно будет использовать std::vector::cbegin()
, потому что begin()
позволит вам изменить исходный вектор, что противоречит типу const std::vector<T>&
return.
getBase()
, и она работала, но она все еще работала без использования cbegin()
. Я что-то пропустил?
vector::begin
имеет перегрузку, которая возвращает константный итератор. Поэтому нет необходимости использовать vector::cbegin
(хотя это тоже будет работать). После изменения getBase()
код потерпит неудачу, если вы попытаетесь изменить элемент вектора с помощью итератора; например, *it = 0;
внутри цикла не скомпилируется.
const
несмотря на то, что они передаются по значению? Вы пытаетесь сделать код максимально неэффективным? :)