#c #class #memory #memory-management #vector
#c #класс #память #управление памятью #вектор
Вопрос:
Я почти закончил с реализацией типа вектора std::vector (надеюсь), но у меня небольшая ошибка в коде, и я, кажется, не могу найти, где именно. В принципе, когда я создаю Vector и использую push_back, вектор автоматически выделяет новую память для большего количества элементов (в частности, в два раза больше размера вектора), но при этом «дополнительное пространство» инициализируется 0, и я не знаю почему.
Вот мой код:
Vector.h
#include <memory>
#include <cstddef>
template <class T>
class Vec{
public:
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef T value_type;
Vec(){create();}
Vec(size_type n, const Tamp; val = T()) {create(n, val);}
~Vec() {uncreate();}
//copy constructor
Vec(const Vecamp; v) {create(v.begin(), v.end());}
//assignment operator
Vecamp; operator=(const Vecamp;);
size_type size() const {return limit - data;}
//index operators
Tamp; operator[](size_type i) {return data[i];}
const Tamp; operator[](size_type i) const {return data[i];}
iterator begin() {return data;}
const_iterator begin() const {return data;}
iterator end() {return limit;}
const_iterator end() const {return limit;}
void push_back(const Tamp;);
private:
iterator data; //1st element
iterator avail; //one past last constructed element
iterator limit; //one past last available element
//Memory management
std::allocator<T> alloc;
void create();
void create(size_type, const Tamp;);
void create(const_iterator, const_iterator);
void uncreate();
void grow();
void unchecked_append(const Tamp;);
};
template <class T>
void Vec<T>::push_back(const Tamp; val){
if(avail == limit)
grow();
unchecked_append(val);
}
template <class T>
Vec<T>amp; Vec<T>::operator=(const Vecamp; rhs){
//self-assign
if(amp;rhs != this){
uncreate;
create(rhs.begin(), rhs.end());
}
return *this;
}
// Empty Vector, pointers to 0
template <class T> void Vec<T>::create(){
data = avail = limit = 0;
}
// Allocate memory for (size)
template <class T> void Vec<T>::create(size_type n, const Tamp; val){
data = alloc.allocate(n); // returns pointer to first element
limit = avail = data n;
std::uninitialized_fill(data, limit, val);
}
template <class T> void Vec<T>::create(const_iterator i, const_iterator j){
data = alloc.allocate(j-i);
limit = avail =std::uninitialized_copy(i, j, data);
}
template <class T> void Vec<T>::uncreate(){
if(data){
iterator it = avail;
while(it != data)
alloc.destroy(--it);
// Free space
alloc.deallocate(data, limit - data);
}
// Empty Vector
data = limit = avail = 0;
}
template <class T> void Vec<T>::grow(){
// Allocate twice the space we had
size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1));
// Allocate new space and copy to new space
iterator new_data = alloc.allocate(new_size);
iterator new_avail = std::uninitialized_copy(data, avail, new_data);
// Return old space used
uncreate();
// Reset pointers to point to new space
data = new_data;
avail = new_avail;
limit = data new_size;
}
template <class T> void Vec<T>::unchecked_append(const Tamp; val){
alloc.construct(avail , val);
}
И вот как я создал вектор
main.cpp
#include "vector.h"
#incude <iostream>
using namespace std;
int main(){
Vec<int> v1;
v1.push_back(12);
v1.push_back(9);
v1.push_back(74);
v1.push_back(22);
Vec<int> v2 = v1;
v2.push_back(70); //After doing this the vector is (12, 9, 74, 22, 70, 0, 0, 0)
for(auto e: v2) cout << e << " ";
cout << endl;
}
Спасибо за любую помощь, а также любые отзывы о фактическом коде приветствуются. 🙂
Комментарии:
1. Может быть, вы
std::allocator
всегда это делаете, вы проверили? Может быть, это делается в отладочных сборках, не так ли? Вы пробовали просто пошагово использовать свойgrow
метод, чтобы увидеть, как выглядят новые данные на каждом шаге?2. Я не понимаю вашего комментария, как v2 может содержать в себе более одного элемента? Вы добавили только 70? Или дело в том, что 70 заканчивается в v1?
3. Допустил опечатку, отредактировал ее. Я инициализирую его с версии v1.
4. @Бесполезно, на самом деле не уверен. Я только проверяю, что std::vector этого не делает, так что, возможно, в моем коде есть ошибка или я что-то пропустил / сделал что-то лишнее.
5. Я только что дал вам список вещей, которые нужно проверить, так что проверьте их! У вас есть код для вашего распределителя, установленный локально, так что прочтите его. Вы знаете (или должны быть в состоянии найти) свои настройки сборки и документацию по компилятору. У вас, предположительно, есть отладчик, так что используйте его.
Ответ №1:
Проблема в том (я не знаю, действительно ли это проблема)
template <class T> void Vec<T>::grow(){
// Allocate twice the space we had
size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1));
....
....
}
Нет необходимости делать какую-либо векторную копию, чтобы воспроизвести вашу проблему.
Проблема видна даже в первом векторе после вставки 5-го элемента
v1.push_back(12);
v1.push_back(9);
v1.push_back(74);
v1.push_back(22);
v1.push_back(22); //5th elemnt.
теперь выводим размер;
cout<<v1.size()<<endl; - it says 8.
Даже в std-векторе после resize() нормальным поведением является печать нулей для пустых элементов.
Посмотрите на этот пример: http://en.cppreference.com/w/cpp/container/vector/resize
если вам не нужны дополнительные нули, вам нужно настроить вычисление «: new_size».
Комментарии:
1. ДА. Я имел в виду сделать это вычисление new_size. Моя ошибка заключалась в том, что я просто передал неправильную переменную из класса. Я передавал «лимит» вместо «использовать». Предел равен единице после конца для всего массива (включая выделенную память). Доступно на единицу после последнего инициализированного значения.
2. Вот оно. Хорошо.