Review vector

Several objects were incorrectly allocated and destructed
This commit is contained in:
Baptiste Wicht 2016-10-03 19:16:21 +02:00
parent 9785864192
commit 9e03bc57de
No known key found for this signature in database
GPG Key ID: C5566B6C7F884532
2 changed files with 121 additions and 117 deletions

View File

@ -188,12 +188,22 @@ struct deque {
return *this; return *this;
} }
~deque() { void destruct_all(){
for (size_t i = 0; i < _size; ++i) { for (size_t i = 0; i < _size; ++i) {
(*this)[i].~value_type(); (*this)[i].~value_type();
} }
} }
~deque() {
destruct_all();
for(size_t i = 0; i < blocks; ++i){
deallocate(data[i]);
}
delete[] data;
}
void push_back(T&& element) { void push_back(T&& element) {
ensure_capacity_back(1); ensure_capacity_back(1);
@ -201,14 +211,14 @@ struct deque {
auto block = (last_element + 1) / block_elements; auto block = (last_element + 1) / block_elements;
auto index = (last_element + 1) % block_elements; auto index = (last_element + 1) % block_elements;
data[block][index] = std::move(element); new (&data[block][index]) T(std::move(element));
++last_element; ++last_element;
} else { } else {
auto block = last_element / block_elements; auto block = last_element / block_elements;
auto index = last_element % block_elements; auto index = last_element % block_elements;
data[block][index] = std::move(element); new (&data[block][index]) T(std::move(element));
} }
++_size; ++_size;
@ -221,41 +231,19 @@ struct deque {
auto block = (last_element + 1) / block_elements; auto block = (last_element + 1) / block_elements;
auto index = (last_element + 1) % block_elements; auto index = (last_element + 1) % block_elements;
data[block][index] = element; new (&data[block][index]) T(element);
++last_element; ++last_element;
} else { } else {
auto block = last_element / block_elements; auto block = last_element / block_elements;
auto index = last_element % block_elements; auto index = last_element % block_elements;
data[block][index] = element; new (&data[block][index]) T(element);
} }
++_size; ++_size;
} }
reference_type emplace_back() {
ensure_capacity_back(1);
if (_size) {
auto block = (last_element + 1) / block_elements;
auto index = (last_element + 1) % block_elements;
new (&data[block][index]) T();
++last_element;
} else {
auto block = last_element / block_elements;
auto index = last_element % block_elements;
new (&data[block][index]) T();
}
++_size;
return back();
}
template <typename... Args> template <typename... Args>
reference_type emplace_back(Args&&... args) { reference_type emplace_back(Args&&... args) {
ensure_capacity_back(1); ensure_capacity_back(1);
@ -286,14 +274,14 @@ struct deque {
auto block = (first_element - 1) / block_elements; auto block = (first_element - 1) / block_elements;
auto index = (first_element - 1) % block_elements; auto index = (first_element - 1) % block_elements;
data[block][index] = std::move(element); new (&data[block][index]) T(std::move(element));
--first_element; --first_element;
} else { } else {
auto block = first_element / block_elements; auto block = first_element / block_elements;
auto index = first_element % block_elements; auto index = first_element % block_elements;
data[block][index] = std::move(element); new (&data[block][index]) T(std::move(element));
} }
++_size; ++_size;
@ -306,34 +294,14 @@ struct deque {
auto block = (first_element - 1) / block_elements; auto block = (first_element - 1) / block_elements;
auto index = (first_element - 1) % block_elements; auto index = (first_element - 1) % block_elements;
data[block][index] = element; new (&data[block][index]) T(element);
--first_element; --first_element;
} else { } else {
auto block = first_element / block_elements; auto block = first_element / block_elements;
auto index = first_element % block_elements; auto index = first_element % block_elements;
data[block][index] = element; new (&data[block][index]) T(element);
}
++_size;
}
reference_type emplace_front() {
ensure_capacity_front(1);
if (_size) {
auto block = (first_element - 1) / block_elements;
auto index = (first_element - 1) % block_elements;
new (&data[block][index]) T();
--first_element;
} else {
auto block = first_element / block_elements;
auto index = first_element % block_elements;
new (&data[block][index]) T();
} }
++_size; ++_size;
@ -424,9 +392,7 @@ struct deque {
* \brief Removes all the elements of the deque * \brief Removes all the elements of the deque
*/ */
void clear() { void clear() {
for (size_t i = 0; i < _size; ++i) { destruct_all();
(*this)[i].~value_type();
}
first_element = 0; first_element = 0;
last_element = 0; last_element = 0;
@ -509,6 +475,14 @@ struct deque {
} }
private: private:
static value_type* allocate(size_t n){
return static_cast<value_type*>(malloc(n * sizeof(value_type)));
}
static void deallocate(value_type* ptr){
free(ptr);
}
void ensure_capacity_front(size_t n) { void ensure_capacity_front(size_t n) {
auto capacity_front = first_element; auto capacity_front = first_element;
@ -519,7 +493,7 @@ private:
data = new T*[blocks]; data = new T*[blocks];
for (size_t i = 0; i < blocks; ++i) { for (size_t i = 0; i < blocks; ++i) {
data[i] = new T[block_elements]; data[i] = allocate(block_elements);
} }
first_element = blocks * block_elements - 1; first_element = blocks * block_elements - 1;
@ -535,7 +509,7 @@ private:
} }
for (size_t i = 0; i < new_blocks; ++i) { for (size_t i = 0; i < new_blocks; ++i) {
new_data[i] = new T[block_elements]; new_data[i] = allocate(block_elements);
} }
first_element += new_blocks * block_elements; first_element += new_blocks * block_elements;
@ -559,7 +533,7 @@ private:
data = new T*[blocks]; data = new T*[blocks];
for (size_t i = 0; i < blocks; ++i) { for (size_t i = 0; i < blocks; ++i) {
data[i] = new T[block_elements]; data[i] = allocate(block_elements);
} }
first_element = 0; first_element = 0;
@ -575,7 +549,7 @@ private:
} }
for (size_t i = blocks; i < blocks + new_blocks; ++i) { for (size_t i = blocks; i < blocks + new_blocks; ++i) {
new_data[i] = new T[block_elements]; new_data[i] = allocate(block_elements);
} }
delete[] data; delete[] data;

View File

@ -40,40 +40,41 @@ struct vector {
/*! /*!
* \brief Constructs a vector of the given size * \brief Constructs a vector of the given size
*/ */
explicit vector(uint64_t c) : data(new T[c]), _size(0), _capacity(c) {} explicit vector(uint64_t c) : data(allocate(c)), _size(0), _capacity(c) {}
/*! /*!
* \brief Construct a vector containing the given values * \brief Construct a vector containing the given values
*/ */
vector(initializer_list<T> values) : data(new T[values.size()]), _size(values.size()), _capacity(values.size()) { vector(initializer_list<T> values) : data(allocate(values.size())), _size(values.size()), _capacity(values.size()) {
std::copy(values.begin(), values.end(), begin()); std::copy(values.begin(), values.end(), begin());
} }
vector(const vector& rhs) : data(nullptr), _size(rhs._size), _capacity(rhs._capacity) { vector(const vector& rhs) : data(nullptr), _size(rhs._size), _capacity(rhs._capacity) {
if(!rhs.empty()){ if(!rhs.empty()){
data = new T[_capacity]; data = allocate(_capacity);
for(size_t i = 0; i < _size; ++i){ for(size_t i = 0; i < _size; ++i){
data[i] = rhs.data[i]; new (&data[i]) value_type(rhs.data[i]);
} }
} }
} }
vector& operator=(const vector& rhs){ vector& operator=(const vector& rhs){
if(data && _capacity < rhs._capacity){
delete[] data;
data = nullptr;
}
if(_capacity < rhs._capacity){ if(_capacity < rhs._capacity){
if(data){
release();
}
_capacity = rhs._capacity; _capacity = rhs._capacity;
data = new T[_capacity]; data = allocate(_capacity);
} else {
destruct_all();
} }
_size = rhs._size; _size = rhs._size;
for(size_t i = 0; i < _size; ++i){ for(size_t i = 0; i < _size; ++i){
data[i] = rhs.data[i]; new (&data[i]) value_type(rhs.data[i]);
} }
return *this; return *this;
@ -89,7 +90,7 @@ struct vector {
vector& operator=(vector&& rhs){ vector& operator=(vector&& rhs){
if(data){ if(data){
delete[] data; release();
} }
data = rhs.data; data = rhs.data;
@ -104,7 +105,7 @@ struct vector {
~vector(){ ~vector(){
if(data){ if(data){
delete[] data; release();
} }
} }
@ -191,8 +192,11 @@ struct vector {
if(new_size > size()){ if(new_size > size()){
ensure_capacity(new_size); ensure_capacity(new_size);
//The elements will automatically be created to their defaults when // Default initialize the new elements
//the array gets resized in ensure_capacity for(size_t i = _size; i < new_size; ++i){
new (&data[i]) value_type();
}
_size = new_size; _size = new_size;
} else if(new_size < _size){ } else if(new_size < _size){
// Call the necessary destructors // Call the necessary destructors
@ -211,7 +215,7 @@ struct vector {
void push_back(value_type&& element){ void push_back(value_type&& element){
ensure_capacity(_size + 1); ensure_capacity(_size + 1);
data[_size++] = std::move(element); new (&data[_size++]) value_type(std::move(element));
} }
/*! /*!
@ -220,43 +224,7 @@ struct vector {
void push_back(const value_type& element){ void push_back(const value_type& element){
ensure_capacity(_size + 1); ensure_capacity(_size + 1);
data[_size++] = element; new (&data[_size++]) value_type(element);
}
/*!
* \brief Add an element at the front of the vector
*/
void push_front(value_type&& element){
ensure_capacity(_size + 1);
for(size_t i = _size; i > 0; --i){
data[i] = std::move(data[i-1]);
}
data[0] = std::move(element);
++_size;
}
/*!
* \brief Add an element at the front of the vector
*/
void push_front(const value_type& element){
ensure_capacity(_size + 1);
for(size_t i = _size; i > 0; --i){
data[i] = std::move(data[i-1]);
}
data[0] = element;
++_size;
}
value_type& emplace_back(){
ensure_capacity(_size + 1);
new (&data[_size++]) T();
return back();
} }
template<typename... Args> template<typename... Args>
@ -268,6 +236,46 @@ struct vector {
return back(); return back();
} }
/*!
* \brief Add an element at the front of the vector
*/
void push_front(value_type&& element){
ensure_capacity(_size + 1);
if(!empty()){
new (&data[_size]) value_type(std::move(data[_size - 1]));
for (size_t i = _size - 1; i > 0; --i) {
data[i] = std::move(data[i - 1]);
}
}
// At this point data[0] has been deleted
data[0] = std::move(element);
++_size;
}
/*!
* \brief Add an element at the front of the vector
*/
void push_front(const value_type& element){
ensure_capacity(_size + 1);
if(!empty()){
new (&data[_size]) value_type(std::move(data[_size - 1]));
for (size_t i = _size - 1; i > 0; --i) {
data[i] = std::move(data[i - 1]);
}
}
// At this point data[0] has been deleted
data[0] = element;
++_size;
}
/*! /*!
* \brief Removes the last element of the vector * \brief Removes the last element of the vector
*/ */
@ -282,9 +290,7 @@ struct vector {
* \brief Removes all the elements of the vector * \brief Removes all the elements of the vector
*/ */
void clear(){ void clear(){
for(size_t i = 0; i < _size; ++i){ destruct_all();
data[i].~value_type();
}
_size = 0; _size = 0;
} }
@ -383,10 +389,33 @@ struct vector {
} }
private: private:
static value_type* allocate(size_t n){
return static_cast<value_type*>(malloc(n * sizeof(value_type)));
}
static void deallocate(value_type* ptr){
free(ptr);
}
void destruct_all(){
// Call the destructors
for(size_t i = 0; i< _size; ++i){
data[i].~value_type();
}
}
void release(){
destruct_all();
// Deallocate the memory
free(data);
data = nullptr;
}
void ensure_capacity(size_t new_capacity){ void ensure_capacity(size_t new_capacity){
if(_capacity == 0){ if(_capacity == 0){
_capacity = new_capacity; _capacity = new_capacity;
data = new T[_capacity]; data = allocate(_capacity);
} else if(_capacity < new_capacity){ } else if(_capacity < new_capacity){
// Double the current capacity // Double the current capacity
_capacity= _capacity * 2; _capacity= _capacity * 2;
@ -396,10 +425,11 @@ private:
_capacity = new_capacity; _capacity = new_capacity;
} }
auto new_data = new T[_capacity]; auto new_data = allocate(_capacity);
std::move_n(data, _size, new_data); std::move_n(data, _size, new_data);
delete[] data; release();
data = new_data; data = new_data;
} }
} }