I've implemented a simple vector-like structure
It works well if i use vector<int> or vector<char>
but when i use <vector<vector<int>> it makes error
Is there are good implementation code about vector stl or problem in my code?
here is my code
class _vector {
private:
int _size;
int _capacity;
T* vc;
public:
_vector(int size = 1) {
_size = 0;
_capacity = size;
vc = new T[size];
}
~_vector() {
delete[] vc;
}
int size() { return _size; }
bool empty() { return !_size; }
void resize(int size) {
_capacity = size;
T* tmp = new T[size];
for (int i = 0; i < _size; i++) tmp[i] = vc[i];
delete[] vc;
vc = tmp;
}
void clear() {
delete[] vc;
_capacity = 1;
_size = 0;
vc = new T[_capacity];
}
void push_back(T val) {
if (_size == _capacity) resize(2 * _capacity);
vc[_size++] = val;
}
void pop_back() {
if (_size == 0) return;
vc[--_size] = 0;
}
T& operator[](int i) const { return vc[i]; }
_vector<T>& operator=(_vector<T> &tmp) {
_capacity = tmp._capacity;
_size = tmp._size;
delete[] vc;
vc = new T[_capacity];
for (int i = 0; i < _size; i++) vc[i] = tmp[i];
return *this;
}
Your implementation is not following the Rule of 3, as it is missing a copy constructor, and a proper copy assignment operator (which can be implemented utilizing the copy constructor). And in C++11 and later, the Rule of 5, by adding a move constructor and a move assignment operator.
Also, your implementation does not work correctly with non-trivial types that have constructors/destructors defined, such as when T is another _vector type, or any other type that has pointers/resources allocated inside of it. So, your class needs to construct new objects when adding elements to the array, using placement-new, and destruct objects when removing elements from the array, by directly calling their destructors.
Try something more like this instead:
template <typename T>
class _vector {
public:
typedef unsigned int size_type;
typedef T value_type;
private:
size_type _size;
size_type _capacity;
value_type* vc;
public:
_vector(size_type initalcap = 0) : _size(0), _capacity(0), vc(0) {
reserve(initialcap);
}
_vector(const _vector<T> &src) : _size(0), _capacity(0), vc(0) {
reserve(src._capacity);
for(size_type i = 0; i < src._size; ++i) {
new(vc[i]) value_type(src.vc[i]);
}
_size = src._size;
}
// C++11 and later only...
_vector(_vector<T> &&src) : _size(src._size), _capacity(src._capacity), vc(src._vc) {
src._size = 0;
src._capacity = 0;
src.vc = 0;
}
~_vector() {
clear();
delete[] reinterpret_cast<char*>(vc);
}
size_type size() const { return _size; }
size_type capacity() const { return _capacity; }
bool empty() const { return !_size; }
void reserve(size_type newcap) {
if (newcap <= _capacity) return;
value_type* tmp = reinterpret_cast<value_type*>(new char[sizeof(value_type) * newcap]);
for (size_type i = 0; i < _size; ++i) {
new(tmp[i]) value_type(vc[i]);
}
delete[] reinterpret_cast<char*>(vc);
vc = tmp;
_capacity = newcap;
}
void resize(size_type newsize) {
if (newsize < _size) {
for(size_type i = _size; i-- > newsize; ) {
vc[i].~value_type();
}
_size = newsize;
}
else if (newsize > _size) {
reserve(newsize);
for (size_type i = _size; i < newsize; ++i) {
new(vc[i]) value_type();
}
_size = newsize;
}
}
void clear() {
resize(0);
}
void push_back(const T &val) {
if (_size == _capacity) reserve(2 * _capacity);
new(vc[_size]) value_type(val);
++_size;
}
void pop_back() {
if (_size) {
vc[--_size].~value_type();
}
}
value_type& operator[](size_type i) { return vc[i]; }
const value_type& operator[](size_type i) const { return vc[i]; }
_vector<T>& operator=(const _vector<T> &rhs) {
if (&rhs != this) {
_vector<T> tmp(rhs);
std::swap(tmp.vc, vc);
std::swap(tmp._size, _size);
std::swap(tmp._capacity, _capacity);
}
return *this;
}
// C++11 and later only...
_vector<T>& operator=(_vector<T> &&rhs) {
_vector<T> tmp(std::move(rhs));
std::swap(tmp.vc, vc);
std::swap(tmp._size, _size);
std::swap(tmp._capacity, _capacity);
return *this;
}
};
Related
So I'm trying to write my own array template and everything works until i try to create a const object of my class template. in main.cpp I create the object with the copy contructor and I change it which I would expect to not work but it works. Help would be appreciated :D
main.cpp
# include "Array.hpp"
int main( void ) {
Array<int> l = 1;
l.setValue(5, 0);
const Array<int> abc(l);
std::cout << abc[0] << std::endl;
abc[0] = 3;
std::cout << abc[0] << std::endl;
return (0);
}
Array.tpp
#ifndef ARRAY_TPP
# define ARRAY_TPP
# include "Array.hpp"
template<class T>
class Array {
private:
int size_;
T *array_;
public:
Array() : size_(0), array_(new T[size_]) {};
Array(int n) : size_(n), array_(new T[size_]) {};
Array(Array const& src) : size_(src.size()), array_(new T[src.size()]) {
for (int i = 0; i < src.size(); ++i) {
array_[i] = src[i];
}
};
Array& operator=(Array const& copy) {
size_ = copy.size();
delete[] array_;
array_ = new T[size_];
for (int i = 0; i < size_; i++)
array_[i] = copy[i];
return (*this);
}
T& operator[](int n) const {
if (n < 0 || n >= size_)
throw std::out_of_range("out of range");
return (array_[n]);
}
int size(void) const { return (size_); };
void setValue(T value, int n) {
if (n < 0 || n >= size_)
throw std::out_of_range("out of range");
array_[n] = value;
}
~Array() { delete[] array_; };
};
#endif
The issue is this:
T& operator[](int n) const {
if (n < 0 || n >= size_)
throw std::out_of_range("out of range");
return (array_[n]);
}
Because this is declared to be a const method, it can be called on a const Array. Though, it returns a non-const reference to the element. Because Array stores the elements via a T *, only that pointer is const in a const Array while modifiying the elements via that pointer is "fine".
You need two overloads of operator[]:
T& operator[](int n);
const T& operator[](int n) const;
I am trying to merge two dynamic arrays but I am getting an error in my merge function that
"data': is not a member of 'List<T>"
I know that the error is ocuring because the given parameter in the merge(const List& other) is list but I am confused how to access my ArrayList2 which has been passed in merge function in the main
my code is:
#include <iostream>
using namespace std;
template<class T>
class List {
public:
// return the capacity of the list
virtual size_t capacity() const = 0;
// return the number of elements in the list
virtual size_t size() const = 0;
// inserts an element to the beginning
virtual void push_front(const T& value) = 0;
// adds an element to the end
virtual void push_back(const T& value) = 0;
// removes the last element
virtual void pop_back() = 0;
// removes the first element
virtual void pop_front() = 0;
// remove the first occurrence of an element with the given value
virtual void remove(const T& val) = 0;
// merges two sorted lists
virtual void merge(const List<T>& other) = 0;
virtual ~List() {}
};
template<class T>
class ArrayList : public List<T>
{
private:
T* data;
size_t max_capacity;
size_t num_of_element;
public:
ArrayList() = delete; // disable default constructor
// constructor
ArrayList(size_t capacity) : max_capacity(capacity), num_of_element(0) {
data = new T[capacity];
}
// copy constructor
ArrayList(const ArrayList<T>& other_list) : max_capacity(other_list.max_capacity),
num_of_element(other_list.num_of_element) {
data = new T[max_capacity];
for (size_t i = 0; i < other_list.num_of_element; i++) {
data[i] = other_list.data[i];
}
}
// destructor
virtual ~ArrayList() {
delete[]data;
}
size_t capacity() const override {
return max_capacity;
}
size_t size() const override {
return num_of_element;
}
T& operator[](int index) {
return data[index];
}
bool operator==(const ArrayList<T>& other_list) {
// not comparing capacity as eventually array list can be made capacity irrelevant using dynamic allocation
if (num_of_element != other_list.num_of_element) {
return false;
}
for (int i = 0; i < num_of_element; i++) {
if (data[i] != other_list.data[i]) {
return false;
}
}
return true;
}
void push_front(const T& value)
{
}
void push_back(const T& value)
{
if (max_capacity > num_of_element)
{
num_of_element++;
data[num_of_element - 1] = value;
}
}
void pop_back()
{
}
void pop_front()
{
}
void remove(const T& val)
{
int i = 0, j;
while (i < max_capacity)
{
if (data[i] == val)
{
for (int j = i; j < num_of_element-1; j++)
data[j] = data[j + 1];
if (data[i] == val && (i + 1) > num_of_element - 1)
{
data[i] = {};
num_of_element--;
break;
}
num_of_element--;
}
else
i++;
}
}
void merge(const List<T>& other)
{
int i;
int newsize = size() + other.size();
T* temp = new T[newsize];
for (i = 0; i < num_of_element; i++)
temp[i] = data[i];
for (int j = 0; j < other.size(); j++)
{
temp[i] = other.data[j]; //I am getting error on this line
i++;
}
}
private:
void shift_left_to(size_t start) {
for (size_t i = start; i < num_of_element - 1; i++) {
data[i] = data[i + 1];
}
}
};
int main() {
ArrayList<int> list1(3);
list1.push_back(3);
list1.push_back(1);
list1.push_back(1);
ArrayList<int> list2(2);
list2.push_back(1);
list2.push_back(8);
list1.merge(list2);
/* for (size_t i = 0; i < list1.size(); i++)
cout<<list1[i]<<" ";
cout<<"Size:"<<list1.size()<<" Capacity:"<<list1.capacity();*/
system("pause");
return 0;
}
Presumably, all of your concrete List<T> classes (e.g. ArrayList<T>) will have some kind of accessors to the elements. You can make those accessors part of the List<T> interface and call them in the implementation of void merge(List<T> const&). As an example:
template <class T>
class List {
public:
// ...
virtual T& operator[](int index) = 0;
virtual T const& operator[](int index) const = 0;
};
template <class T>
class ArrayList : public List<T> {
private:
T* data;
size_t max_capacity;
size_t num_of_element;
public:
// ...
T& operator[](int index) override { return data[index]; }
T const& operator[](int index) const override { return data[index]; }
// ...
void merge(const List<T>& other) {
int i;
int newsize = size() + other.size();
T* temp = new T[newsize];
for (i = 0; i < num_of_element; i++) temp[i] = data[i];
for (int j = 0; j < other.size(); j++) {
temp[i] = other[j]; // < Use your List<T>::operator[] here
i++;
}
}
// ...
};
I'd say the message is quite descriptive: List does not have a member called data. You should use the [] operator instead to access the list elements in the merge function. [] operator is implemented by descendants of List.
temp[i] = other[j]
this is the header of a class that I have been designing for an assignment. I have included constructors, a destructors, as well as overloaded operators. Could you give me a hint how to properly define the constructors in a class using c++ 20 most recent features in an efficient way.
#ifndef VECTOR_DOUBLE_H
#define VECTOR_DOUBLE_H
#include <memory>
#include <vector>
class vector_double {
public:
vector_double(int size);
vector_double(std::initializer_list<double> lst);
vector_double(const double* array, int size);
vector_double(const vector_doubler& other);
vector_doubleoperator=(const vector_double& other);
// because I use a managed pointer I don't need a destructor
~vector_double() noexcept = default;
void set(int index, double val);
double& get(int index);
const double& get(int index) const;
int size() const;
void reset(double val);
void fill_from(std::initializer_list<double> lst);
void fill_from(const double* array, int size);
int copy_to(std::vector<double>& vec) const;
double& operator[](int index);
const double& operator[](int index) const;
operator double() const;
vector_double add(const vector_double& other) const;
vector_doubleadd(double number) const;
vector_doublemul_by(double number) const;
void resize(int size);
friend std::ostream& operator<<(std::ostream& out, const vector_double& vec);
private:
std::unique_ptr<double[]> m_array;
int m_size;
};
inline std::ostream& operator<<(std::ostream& out, const vector_double& vec){
if (vec.m_size == 0){
out << "{ }";
}
else{
auto first = true;
out << '{';
for (int i=0; i < vec.m_size; ++i){
if (!first)
out << ", ";
else
first = !first;
out << vec.m_array[i];
}
out << '}';
}
return out;
}
#endif //VECTOR_DOUBLE_H
This example definition may help, I tried sticking to C++20 features:
#include <cmath>
#include "vector_double.h"
vector_double::vector_double(int size):
m_array{ new double[size] },
m_size{size}
{}
vector_double::vector_double(std::initializer_list<double> lst): //Constructor that takes an init list
vector_double(lst.size())
{
std::copy(lst.begin(), lst.end(), m_array.get());
}
vector_double::vector_double(const double* array, int size): //Constructor that takes array and size
vector_double(size)
{
// std::copy(array, array + size, m_array.get());
std::copy(&array[0], &array[size], m_array.get());
}
vector_double::vector_double(const vector_double& other): //Copy Constructor
vector_double(other.m_size)
{
std::copy(&other.m_array[0], &other.m_array[m_size], &m_array[0]);
}
vector_double& vector_double::operator=(const vector_double& other) {
if (this != &other) {
if (m_size != other.m_size) {
auto* array = new double[other.m_size];
m_array.reset(array);
m_size = other.m_size;
}
std::copy(&other.m_array[0], &other.m_array[m_size], &m_array[0]);
}
return *this;
}
void vector_double::set(int index, double val) {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
m_array[index] = val;
}
double& vector_double::get(int index) {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
return m_array[index];
}
const double& vector_double::get(int index) const {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
return m_array[index];
}
int vector_double::size() const {
return m_size;
}
void vector_double::reset(double val) {
for (int i=0; i<m_size; ++i){
m_array[i] = val;
}
}
void vector_double::fill_from(std::initializer_list<double> lst) {
int size = std::min((int)lst.size(), m_size);
std::copy(lst.begin(), lst.begin() + size, &m_array[0]);
}
void vector_double::fill_from(const double* array, int size) {
size = std::min(size, m_size);
for (int i = 0; i < size; ++i) {
m_array[i] = array[i];
}
}
int vector_double::copy_to(std::vector<double>& vec) const {
for (int i = 0; i < m_size; ++i) {
vec.push_back(m_array[i]);
}
return m_size;
}
double& vector_double::operator[](int index) {
return m_array[index];
}
const double& vector_double::operator[](int index) const { //Overloading "[]" operator
return m_array[index];
}
vector_double::operator double() const {
double sum = 0.0;
for (int i = 0; i < m_size; ++i) {
sum += m_array[i] * m_array[i];
}
return std::sqrt(sum);
}
vector_double vector_double::add(const vector_double& other) const {
if (m_size != other.m_size)
throw std::logic_error("size mismatch");
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] += other[i];
}
return copy;
}
vector_double vector_double::add(double number) const {
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] += number;
}
return copy;
}
vector_double vector_double::mul_by(double number) const {
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] *= number;
}
return copy;
}
void vector_double::resize(int size) {
if (size != m_size){
auto array = new double[size] {0,};
auto common = std::min(size,m_size);
for (int i = 0; i < common; ++i) {
array[i] = m_array[i];
}
m_array.reset(array);
m_size = size;
}
}
Everything seems to be copying fine, but when I call array2.print(), it shows segmentation fault. What am I doing wrong?
#include <iostream>
#include <initializer_list>
template <typename T>
class DynamicArray
{
private:
const int GROWTH_FACTOR = 2;
const int INITIAL_CAPACITY = 5;
T *m_array;
int m_capacity; // Capacity of the array
int m_size; // Number of added elements
public:
DynamicArray(std::initializer_list<T> elements)
: m_size(elements.size())
, m_capacity(elements.size() * 2)
{
m_array = new T[m_capacity];
std::copy(elements.begin(), elements.end(), m_array);
}
DynamicArray()
: m_size(0)
, m_capacity(INITIAL_CAPACITY)
{
m_array = new T[m_capacity];
}
~DynamicArray()
{
delete[] m_array;
}
DynamicArray(const DynamicArray& other)
: GROWTH_FACTOR(other.GROWTH_FACTOR)
, INITIAL_CAPACITY(other.INITIAL_CAPACITY)
, m_capacity(other.m_capacity)
, m_size(other.m_size)
{
T *m_array = new T[m_capacity];
std::copy(other.m_array, other.m_array + m_size, m_array);
}
int size()
{
return m_size;
}
int capacity()
{
return m_capacity;
}
void resize()
{
int new_capacity = m_capacity * GROWTH_FACTOR;
m_capacity = new_capacity;
T *temp = new T[new_capacity];
std::copy(m_array, m_array + m_capacity, temp);
delete[] m_array;
m_array = temp;
}
void deleteAt(int pos)
{
for (int i = pos; i < m_size - 1; i++)
{
(*this)[i] = (*this)[i + 1];
}
m_size--;
}
void insertAt(T value, int pos)
{
if (m_capacity == m_size)
{
resize();
}
for (int i = m_size - 1; i >= pos; i--)
{
(*this)[i + 1] = (*this)[i];
}
m_size++;
(*this)[pos] = value;
}
void append(T value)
{
insertAt(value, m_size);
}
void print() {
for (int i = 0; i < m_size; i++)
{
std::cout << (*this)[i] << ", ";
}
std::cout << std::endl;
}
T& operator[](int index)
{
if (index < 0 || index > m_size - 1)
{
throw std::invalid_argument("Index out of range!");
}
return m_array[index];
}
};
int main()
{
DynamicArray<int> array = { 1, 2, 3, 4 };
DynamicArray<int> array2 = array;
array2.print();
return 0;
}
The error is here
T *m_array = new T[m_capacity];
It should be
m_array = new T[m_capacity];
By declaring a new variable called m_array you hid the class member variable that you wanted to assign to. The technical name for this is shadowing, a good compiler would warn you about this.
You redeclare m_array in the cctor, which shadows the class member.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
In an assigment, I was asked to create my own Vector<T>, Mathvector<T> (which inherits from vector) and a Polynomial class type.
I'm getting the following error and couldn't figure out why.
MathVector.h:37:32: error: invalid operands to binary expression ('mathVector<double>' and 'mathVector<double>')
if (this[j]>this[j+1])
Ihe sort function is in "mathVector.h" and its goal is to sort the vector in ascending or descending order.
This is the error part of the "MathVector.h":
void sort(int index) {
int i,j;
int n=this->get_size();
if (index==1) {
for (i=0; i<n-1; i++)
for (j=0; j<n-i-1; j++) {
if (this[j]>this[j+1]) {
T temp;
temp=this[j+1];
this[j+1]=this[j];
this[j]=temp;
}
}
}
else {
for (i=0; i<n-1; i++)
for (j=0; j<n-i-1; j++) {
if (this[j]<this[j+1]) {
T temp;
temp=this[j+1];
this[j+1]=this[j];
this[j]=temp;
}
}
}
return;
}
This is the "vector.h":
template<class T>
class Vector {
private:
int _size;
int _capacity;
T *_data;
static T *allocate(int size) {
return static_cast<T *>(malloc(sizeof(T) * size));
}
static void copyRange(T *begin, T *end, T *dest) {
while (begin != end) {
new((void *) dest) T(*begin);
++begin;
++dest;
}
}
static void deleteRange(T *begin, T *end) {
while (begin != end) {
begin->~T();
++begin;
}
}
public:
Vector() {
_size = 0;
_capacity = 0;
_data = 0;
}
~Vector() {
deleteRange(_data, _data + _size);
free(_data);
}
Vector(const Vector &obj) {
this->_size = obj.get_size();
this->_data = obj.get_data();
this->_capacity = obj.get_capacity();
}
void insert(const T &value) {
if (_size != _capacity) {
new((void *) (_data + _size)) T(value);
++_size;
return;
}
int newCapacity;
if (_capacity == 0) { newCapacity = 1; }
else (newCapacity = _capacity * 2);
T *newData = allocate(newCapacity);
copyRange(_data, _data + _size, newData);
new((void *) (newData + _size)) T(value);
deleteRange(_data, _data + _size);
free(_data);
_data = newData;
_capacity = newCapacity;
++_size;
}
void resize(int index) {
if (index == _capacity) { return; }
else if (index > _capacity) { _capacity = index; }
else {
_capacity = index;
if (index < _size) {
deleteRange(_data + index, _data + _size);
_size = index;
}
}
}
T &operator[](int index) {
T empty;
if ((index < 0) || (index >= _size)) {
cout<<"Wrong Index";
return empty;
}
return _data[index];
}
const T &
operator[](int index) const {
T empty;
if ((index < 0) || (index >= _size)) {
cout<<"Wrong Index";
return empty;
} else return _data[index];
}
Vector &operator=(const Vector &other) {
this->_size = other.get_size();
this->_data = other.get_data();
this->_capacity = other.get_capacity();
return *this;
}
friend ostream &operator<<(ostream &os, const Vector &other) {
os << "Size: " << other._size << " | Capacity: " << other._capacity << " | ";
int i;
for (i = 0; i < other._size; i++) {
os << other[i] << ",";
}
return os;
}
T *begin() const {
return _data;
}
T *end() const {
return _data + _size;
}
int get_size() const {
return _size;
}
T* get_data() const {
return _data;
}
int get_capacity() const {
return _capacity;
}
};
this[j] is hardly ever the right thing to do. It can only be correct, if *this happens to be a subobject within an array, and have at least j siblings after it. this[j] is equivalent to *(this + j). As you can see, it dereferences a pointer to jth sibling after *this.
I suspect, that you instead intended to access the elements of the buffer by calling Vector::operator[]. You'd do that by dereferencing the pointer first: (*this)[j].