Template function calling - c++

#include <iostream>
#include <memory>
#include <initializer_list>
#include <cassert>
template <typename T>
class Vector
{
// Your implementation of the Vector class starts here
private:
//attributes
int length;
T* data;
public:
//constructors
Vector()
:length(0),
data(nullptr)
{
std::cout<<"New empty object created"<<std::endl;
}
Vector(int length)
:length(length),
data(new T[length])
{
std::cout<< "Length of object is = " <<length <<std::endl;
}
//use a copy of another Vector
Vector(const Vector& other)
: Vector(other.length)
{
for(int i=0;i<length;i++)
data[i]=other.data[i];
}
// using initializer list
Vector(std::initializer_list<T> list)
: Vector((int)list.size())
{
std::uninitialized_copy(list.begin(), list.end(), data);
std::cout<< "The elements in the object are: ";
for (auto it = std::begin(list); it!=std::end(list); ++it)
std::cout << ' ' << *it;
std::cout<<std::endl;
}
//operators
//copy
Vector<T>& operator=(const Vector<T>& other)
{
if(this!= &other)
{
std::cout<<"Copied constructor"<<std::endl;
delete[] data;
length = other.length;
std::cout<<"New length ="<<length<<std::endl;
data = new T[length];
std::cout<<"The elements in the object are: ";
for(int i=0;i<length;i++)
{
data[i]=other.data[i];
std::cout<<data[i]<<" ";
}
}
std::cout<<std::endl;
//std::cout << "copy operator" << std::endl;
return *this;
}
//move
Vector<T>& operator=(Vector<T>&& other)
{
if(this!= &other)
{
delete[] data;
length = other.length;
data = new T[length];
for(int i=0;i<length;i++){
data[i]=other.data[i];}
other.length = 0;
delete[] other.data;
other.data = nullptr;
}
//std::cout << "Move operator" << std::endl;
return *this;
}
///////////////////////////////////////////////
//add
Vector<T> operator+(const Vector<T>& other) const
{
assert(length == other.length);
Vector<T> newer(length);
std::cout<<"The addition gives: ";
for(auto i=0;i<length;i++)
{
newer.data[i] = data[i]+other.data[i];
std::cout<<newer.data[i]<<" ";
}
std::cout<<std::endl;
return newer;
}
//minus
Vector<T> operator-(const Vector<T>& other) const
{
assert(length == other.length);
Vector<T> newer(length);
for(auto i=0;i<length;i++)
newer.data[i] = data[i]-other.data[i];
return newer;
}
// Multiply by a scalar
Vector<T> operator*(T scalar)
{
Vector<T> newer(length);
std::cout<<"Multiplication of a new vector by scalar provides: ";
for (auto i=0; i<length; i++)
{
newer.data[i] = data[i] * scalar;
std::cout<<newer.data[i]<<" ";
}
std::cout<<std::endl;
return newer;
}
//////////////////////////////////////////
// Add to existing Vector
Vector<T>& operator+=(const Vector<T>& other)
{
for (auto i=0; i<length; i++)
data[i] += other.data[i];
return *this;
}
// Multiply existing Vector by a scalar
Vector<T>& operator*=(T scalar)
{
std::cout<<"Multiplication of an existing vector by scalar provides: ";
for (auto i=0; i<length; i++)
{
data[i] *= scalar;
std::cout<<data[i]<<" ";
}
std::cout<<std::endl;
return *this;
}
double Valueform(int i)
{
return data[i];
}
int Lengthfinder()
{
return length;
}
///////////////////////////////////////////
//destructor
~Vector()
{
delete[] data;
data = nullptr;
length = 0;
}
};
template<typename T>
T dot(const Vector<T>& lhs, const Vector<T>& rhs)
{
// Your implementation of the dot function starts here
T result = 0;
for (auto i=0; i<lhs.Lengthfinder(); i++)
{
result = lhs.Valueform(i)*rhs.Valueform(i);
//result + = multiply(lhs.data[i],rhs.data[i]);
// result += lhs.data[i]*rhs.data[i];
}
return result;
}
//failsafe for value multiplied by a vector
template <typename T, typename I>
Vector<T> operator*(I i,Vector<T> other)
{
std::cout<<"Multiplication was done by a vector and failsafe activated"<<std::endl;
return(other* T(i)) ;
}
int main()
{
Vector<double> a(5);
Vector<double> b({ 1 , 2 , 3 , 4 });
Vector<double> c({ 2 , 3 , 4 });
Vector<double> d({ 5 , 2 , 1 });
// std::cout<< "a=c" <<std::endl;
a = c;
// std::cout<< "e = c+d" <<std::endl;
Vector<double> e;
e = c+d;
// std::cout<< "f = c*5" <<std::endl;
Vector<double> f;
f = c*5;
// std::cout<< "g = 5*d" <<std::endl;
Vector<double> g;
g = 5*d;
Vector<double> Dott;
Dott = dot(c,d);
return 0;
}
The code does not allow me to call for the functions Valueform and Lengthfinder, anyone has a possible work around where I can get specific data values and length since the class variables are private? The functions are mostly worked around the template but I would like to just call 2 functions to get certain attributes and they are giving me errors that shouldn't exist, althought I'm not sure why exactly.

Your dot function is taking constant vectors:
template<typename T>
T dot(const Vector<T>& lhs, const Vector<T>& rhs)
{ // ^^^^^-----------------^^^^^----- these are const
// Your implementation of the dot function starts here
}
But, your member functions are not marked as const. You should declare them const to make these functions available:
double Valueform(int i) const
{
return data[i];
}
int Lengthfinder() const
{
return length;
}

Related

C++: Disassemble a flat vector into multiple vectors of equal size without copying

Is it possible in C++ to split a flat vector (or C style array) into multiple vectors of equal size without copying any of its containing data? That is, disassembling the original vector by moving its content to a new vector, which invalidates the original vector. The following code example should illustrate this:
#include <cassert>
#include <vector>
void f(int* v) {
for (int i = 0; i < 100; i++) {
v[i] = i;
}
}
/**
* Split v into n vectors of equal size without copy its data (assert v.size() % n == 0)
*/
std::vector<std::vector<int>> g(std::vector<int> v, int n) {
std::vector<std::vector<int>> vs(n);
int vec_size = v.size() / n;
for (int i = 0; i < n; i++) {
vs[i].assign(v.begin() + i * vec_size, v.begin() + (i + 1) * vec_size); // copies?
// how to let vs[i] point to v.begin() + i * vec_size?
}
return vs;
}
int main() {
std::vector<int> v(100);
f(v.data());
std::vector<std::vector<int>> vs = g(std::move(v), 10);
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
assert(vs[i][j] == i * 10 + j);
}
}
return 0;
}
Yes, in my opinion this is possible. Moving the elements, but not copying the elements.
C++ offers std::make_move_iterator. Please read here about that.
To check that, I created a small class to output, to see, if we copy or move something.
So, if your data can "move", then it will work, otherwise of course a copy will be made. With the following we see the result.
struct Test {
int data{};
Test(int d) : data(d) { std::cout << "Construct and init\n"; }
Test() { std::cout << "Default construct\n"; };
~Test() { std::cout << "Destruct\n"; };
Test(const Test& other) { std::cout << "Construct\n"; data = other.data; }
Test(const Test&& other) noexcept { std::cout << "Move Construct\n"; data = other.data; }
Test& operator =(const Test& other) noexcept { std::cout << "Assign\n"; data = other.data; return *this; }
Test& operator =(const Test&& other) noexcept { std::cout << "Move Assign\n"; data = other.data; return *this; }
};
We will additionally add a small function, which calculates the offsets of the chunks that will be moved.
And then, we can come up with a small function to implement that.
#include <iostream>
#include <vector>
#include <numeric>
#include <iterator>
#include <iomanip>
// Calculate start and end index for all chunks
std::vector<std::pair<size_t, size_t>> calculatePairs(const size_t low, const size_t high, const size_t numberOfGroups) {
// Here we will store the resulting pairs with start and end values
std::vector<std::pair<size_t, size_t>> pairs{};
// Calculate chung size and remainder
const size_t delta = high - low;
const size_t chunk = delta / numberOfGroups;
size_t remainder = delta % numberOfGroups;
// Calculate the chunks start and end addresses for all chunks
size_t startIndex{}, endIndex{};
for (size_t i = 0; i < numberOfGroups; ++i) {
// Calculate end address and distribute remainder equally
endIndex = startIndex + chunk + (remainder ? 1 : 0);
// Store a new pair of start and end indices
pairs.emplace_back(startIndex, endIndex);
// Next start index
startIndex = endIndex;
// We now consumed 1 remainder
if (remainder) --remainder;
}
//--pairs.back().second;
return pairs;
}
struct Test {
int data{};
Test(int d) : data(d) { std::cout << "Construct and init\n"; }
Test() { std::cout << "Default construct\n"; };
~Test() { std::cout << "Destruct\n"; };
Test(const Test& other) { std::cout << "Construct\n"; data = other.data; }
Test(const Test&& other) noexcept { std::cout << "Move Construct\n"; data = other.data; }
Test& operator =(const Test& other) noexcept { std::cout << "Assign\n"; data = other.data; return *this; }
Test& operator =(const Test&& other) noexcept { std::cout << "Move Assign\n"; data = other.data; return *this; }
};
std::vector<std::vector<Test>> split(std::vector<Test>& v, unsigned int n) {
std::vector<std::vector<Test>> result{};
if (v.size() > n) {
result.resize(n);
std::vector<std::pair<size_t, size_t>> offset = calculatePairs(0u, v.size(), n);
for (size_t i{}; i < n; ++i) {
result[i].insert(result[i].end(), std::make_move_iterator(v.begin() + offset[i].first),
std::make_move_iterator(v.begin() + offset[i].second));
}
}
return result;
}
constexpr size_t NumberOfElements = 30u;
constexpr unsigned int NumberOfGroups = 3;
static_assert (NumberOfElements >= NumberOfGroups, "Number of elements must be greater/equal then number of elements\n");
int main() {
std::cout << "\n\n\nCreate vector with " << NumberOfElements << " elements\n\n";
std::vector<Test> v1(NumberOfElements);
std::cout << "\n\n\nFill vector with std::iota\n\n";
std::iota(v1.begin(), v1.end(), 1);
std::cout << "\n\n\nSplit in " << NumberOfGroups<< "\n\n";
std::vector<std::vector<Test>> s = split(v1, NumberOfGroups);
std::cout << "\n\n\nOutput\n\n";
for (const std::vector<Test>& vt : s) {
for (const Test& d : vt) std::cout << std::setw(3) << d.data << ' ';
std::cout << "\n\n";
}
}
But my strong guess is that you want to splice the data. The underlying elements fo the std::vector which you can get with the data() function.
You can access the data easily with pointer arithmetic on data().
But if you want to have the data in a new container, then this is difficult with a std::vector. It can for example be done with a std::list that has a splice function and does, what you want.
Or, you need to implement your own dynamic array and implement a splice function . . .
Checksum:
;23M#eTo1?:B#r7C8#wtJ'Z'..uIvLT.j;bld$Bvgjd.qm=8;B/`dHM%D#wyv:\5YI:WVGwJL00%IsKQ9O+&#g,/gzkPg^cg::LX?6dL3;Fs3GOOAmQmCIW?&skWxZXsElyn6S3#fi:0DSKJ/A^r#*'k#a#e8!XDpjAUtu?K5iu+e=P"M7a2BWdFdA.5NP:Y"l,,h+Y/PxhVfP/m0ceS=Nxol2vOZwM2+!H\^a=douX%fhqcr4'0eXiEZeKvTf0^%CTNY^WB6fc#IpK^GQgxTXQo0ikr0+/OxXlc1B$5jc1r,GQj+fwEdoCPrz6,j:SO6L3QU#7lT:f#Y^V!Au\P'a5amR$NCU?\WspBOuy#RH3tJimka#rdyNN56.$;DtRCHN*YeWlrG=',XNSrzEK:Cw;#A%.#/:c,a2W24IIIdecc7O"EnKQn;nXmUemX4kclDsYci+izmr#vlGAQ.w2!cuf;6n2UvJM,CeSyRj1,:2\9#i8GLwtux!uEHUp7X*5SC%nld956CHsy&/n73/90cRP'Me"1PW+##FH8mH4Rf^o=ZP/Rm\X&1syUdUh+.N/jtoO:,OBBAmq,jW69Fu%jJukBa$g4hIrIPcxx17i;XU,FCbQGd8v*AyKGSML\JN#jte*F";Zh7fqhvCXobE&SapX90r"Z$.CN,1R^aj.=5L6^tUB2UPJH^eb'*B!v5=D.9PFI#Pt*KjK+yS*tV6f.5kgPOzBE$uK0MA/\l9U"63LUR6k3#'cub?u&xILMXP%#:lx2TbKhFOjBpMN!+%F16jrgv&AoFhuf%P!==8?x,NsSd%hVo"BJhVv3rjrhvM"WLE3%y#N7g37Re^XiS9lpyKA9E7ow6U=I"tlv",&#+fZoIR4KM58!NTm978wCI?9wo.ocS!9i5k#ler47J.G0yXjZVSdr=G"uRodC06k\V%8;oUwV&z!W5:+ZvE:nyO#+lO+Hn0&tnH&^tNC?'PmERxs/B+KW4O6&oWDED9?MqxmYgVKoT.a%iw

Move semantics for a custom vector and allocators

I'm implementing a basic std::vector by using an allocator, following PPP by Stroustrup, and in particular I'm sure that all the functions like resize, push_back, emplace_back, and so on are okay.
What is really puzzling me a bit is the copy and move semantics: it works now, but I find it a bit too hard-coded and, more importantly, it's leaking 1 byte in the move assignment, as can be seen from this
==7853== LEAK SUMMARY:
==7853== definitely lost: 1 bytes in 1 blocks
==7853== indirectly lost: 0 bytes in 0 blocks
==7853== possibly lost: 0 bytes in 0 blocks
In the following the whole code. I'd like to see especially how the move assignment should be implemented, because I believe that a problem is the fact that I have to move an allocator, and I'm totally new to this topic.
#include <iostream>
#include <memory>
#include <utility>
#include <initializer_list>
#include <string>
template <typename T, typename Allocator = std::allocator<T>>
class Vector
{
private:
Allocator allocator; //used to handle memory for the elements
T *elem;
std::size_t _size{};
std::size_t _capacity{};
void reserve(const std::size_t n)
{
if (_capacity < n) //if the capacity is smaller than what I want to allocate
{
T *tmp{std::allocator_traits<Allocator>::allocate(allocator, n)};
for (std::size_t i = 0; i < _size; ++i)
{
// allocator.construct(tmp + i, std::move(elem[i])); //tmp[i] = std::move(elem[i]);
std::allocator_traits<Allocator>::construct(allocator, tmp + i, elem[i]);
}
for (std::size_t i = 0; i < _size; ++i)
{
std::allocator_traits<Allocator>::destroy(allocator, elem + i);
}
std::allocator_traits<Allocator>::deallocate(allocator, elem, _capacity);
elem = tmp; //move the pointer
_capacity = n; //size increased!
}
}
void check_and_increase_capacity()
{
if (_capacity == 0)
{
reserve(8);
}
else if (_size == _capacity)
{
reserve(2 * _size);
}
}
template <typename O>
void _push_back(O &&x)
{
check_and_increase_capacity();
std::allocator_traits<Allocator>::construct(allocator, elem + _size, std::forward<O>(x));
++_size;
}
public:
explicit Vector(std::initializer_list<T> list) : elem{std::allocator_traits<Allocator>::allocate(allocator, list.size())}, _size{list.size()}, _capacity{list.size()}
{
std::uninitialized_copy(list.begin(), list.end(), begin());
std::cout << "custom cstr"
<< "\n";
}
~Vector() noexcept
{
for (std::size_t i = 0; i < _size; ++i)
{
std::allocator_traits<Allocator>::destroy(allocator, elem + i); //call the destructor
}
std::allocator_traits<Allocator>::deallocate(allocator, elem, _capacity); //deallocate memory
}
T *begin() { return elem; }
const T *begin() const { return elem; }
T *end() { return elem + _capacity; }
const T *end() const { return elem + _capacity; }
Vector(const Vector &v) : allocator{std::allocator_traits<Allocator>::select_on_container_copy_construction(v.allocator)}, elem{std::allocator_traits<Allocator>::allocate(allocator, v._capacity)}
{
T *tmp{std::allocator_traits<Allocator>::allocate(allocator, _capacity)};
_size = v._size;
_capacity = v._capacity;
for (std::size_t i = 0; i < _size; ++i)
{
std::allocator_traits<Allocator>::construct(allocator, tmp + i, std::move(v[i]));
}
std::uninitialized_copy(v.begin(), v.end(), begin()); //copy the elements
//destroy and deallocate tmp
for (std::size_t i = 0; i < _size; ++i)
{
std::allocator_traits<Allocator>::destroy(allocator, tmp + i);
}
std::allocator_traits<Allocator>::deallocate(allocator, tmp, _capacity);
}
Vector &operator=(const Vector &v)
{
T *tmp{std::allocator_traits<Allocator>::allocate(allocator, v._capacity)};
std::uninitialized_copy(v.begin(), v.end(), begin()); //copy the elements
for (std::size_t i = 0; i < v._size; ++i)
{
std::allocator_traits<Allocator>::destroy(allocator, elem + i);
}
std::allocator_traits<Allocator>::deallocate(allocator, elem, _capacity);
elem = tmp;
_size = v._size;
_capacity = v._capacity;
return *this;
}
Vector(Vector &&v) noexcept : allocator{std::move(v.allocator)}
{
elem = v.elem;
v.elem = nullptr;
_size = v._size;
v._size = 0;
_capacity = v._capacity;
v._capacity = 0;
std::cout << elem << "\n";
}
Vector &operator=(Vector &&v) noexcept
{
std::cout << "move assignment"
<< "\n";
allocator = std::move(v.allocator);
elem = v.elem;
v.elem = nullptr;
_size = v._size;
v._size = 0;
_capacity = v._capacity;
v._capacity = 0;
return *this;
}
void push_back(const T &x)
{
_push_back(x);
}
void push_back(T &&x)
{
_push_back(std::move(x));
}
template <typename... Types>
void emplace_back(Types &&...args)
{
check_and_increase_capacity();
std::allocator_traits<Allocator>::construct(allocator, elem + _size, std::forward<Types>(args)...);
}
T &operator[](const std::size_t i) noexcept { return elem[i]; }
const T &operator[](const std::size_t i) const noexcept { return elem[i]; }
friend std::ostream &operator<<(std::ostream &os, const Vector &v)
{
for (std::size_t i = 0; i < v._size; i++)
{
std::cout << v[i] << "\n";
}
return os;
}
void resize(const std::size_t newsize, T val = T{})
{
reserve(newsize);
for (std::size_t i = _size; i < newsize; ++i)
{
std::allocator_traits<Allocator>::construct(allocator, elem + i, val);
}
//destroy all the new extra elements
for (std::size_t i = newsize; i < _size; ++i)
{
std::allocator_traits<Allocator>::destroy(allocator, elem + i); //just destroy them, don't call release the memory!
}
_size = newsize;
}
};
struct Foo
{
std::string _s;
Foo()
{
std::cout << "foo cstr"
<< "\n";
};
explicit Foo(const std::string &s) : _s{s} {}
~Foo() = default;
};
int main()
{
Vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << v << "\n";
v.push_back(11);
std::cout << "After push_back \n"
<< v << "\n";
Vector<Foo> w{{}, {}};
w.emplace_back();
v.resize(6);
std::cout << "After resize \n"
<< v << "\n";
// Copy/Move semantics tests
Vector<int> v1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Vector<int> v2{v1};
std::cout << "After copy cstr \n"
<< v2 << "\n";
v2.push_back(20);
std::cout << "after push_back \n"
<< v2 << "\n";
Vector<int> v3{};
v3 = v1;
std::cout << v3 << "and v1: \n"
<< v1 << "\n";
Vector<int> v4{std::move(v1)};
std::cout << v4 << "and v1: \n"
<< v1 << "\n";
Vector<int> v5{};
v5 = std::move(v4);
std::cout << v5 << "and v4: \n"
<< v4 << "\n";
return 0;
}

Using std::sort to sort Matrix

Is there a way I can sort matrix elements with the sort function from std?
//Using this matrix
vector<vector<string>> mat;
For example if you have
5 2 1
0 0 2
1 4 3
The result would be
0 0 1
1 2 2
3 4 5
To store a matrix, the nesting of std::vector is not the best solution. As any row manages its own size, there is no unique column size intrinsically granted by the matrix class.
Assuming that OP is damned to use an existing type (which may not be changed), I wrote my sample based on this.
One solution (with least implementation effort) would be
to copy the matrix (std::vector<std::vector<std::string> >) into a temporary of type std::vector<std::string>
apply std::sort() to this temporary
assign the sorted vector to matrix again.
Considering that moving of elements may be expensive, an alternative could be
to build up an index-pair vector
std::sort() it with a custom less functor (which considers matrix elements).
Afterwards, the index-pair vector may be used to access the original matrix elements in sorted order.
The latter is shown in my sample code:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
typedef std::vector<std::string> Row;
typedef std::vector<Row> Matrix;
typedef std::pair<size_t, size_t> IndexPair;
struct LessMatrix {
const Matrix &mat;
LessMatrix(const Matrix &mat): mat(mat) { }
bool operator()(const IndexPair &i1, const IndexPair &i2)
{
return mat[i1.first][i1.second] < mat[i2.first][i2.second];
}
};
std::ostream& operator<<(std::ostream &out, const Matrix &mat)
{
for (const Row row : mat) {
for (const std::string elem : row) out << ' ' << elem;
out << '\n';
}
return out;
}
int main()
{
Matrix mat = {
{ "5", "2", "1" },
{ "0", "0", "2" },
{ "1", "4", "3" }
};
// print input
std::cout << "Input:\n" << mat << '\n';
// indexify matrix
std::vector<IndexPair> indices;
for (size_t i = 0, n = mat.size(); i < n; ++i) {
const std::vector<std::string> &row = mat[i];
for (size_t j = 0, m = row.size(); j < m; ++j) {
indices.push_back(std::make_pair(i, j));
}
}
// sort matrix
LessMatrix less(mat);
std::sort(indices.begin(), indices.end(), less);
// print output
Matrix matOut;
{ size_t i = 0; const size_t nCols = 3;
for (const IndexPair &index : indices) {
if (i % nCols == 0) matOut.push_back(Row());
matOut.back().push_back(mat[index.first][index.second]);
++i;
}
}
std::cout << "Output:\n" << matOut << '\n';
// done
return 0;
}
Output:
Input:
5 2 1
0 0 2
1 4 3
Output:
0 0 1
1 2 2
3 4 5
Life demo on coliru
The OP complained about creating a separate index vector. I suspected that a custom random access iterator might be a replacement (to sort the matrix directly). I must admit that I didn't do this before but, out of curiosity, I tried to puzzle this out:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cassert>
typedef std::vector<std::string> Row;
typedef std::vector<Row> Matrix;
struct MatrixIterator {
typedef size_t difference_type;
typedef std::string value_type;
typedef std::string* pointer;
typedef std::string& reference;
typedef std::random_access_iterator_tag iterator_category;
// accessed matrix
Matrix &mat;
// index of row, index of column
size_t i, j;
MatrixIterator(Matrix &mat, size_t i = 0, size_t j = 0): mat(mat), i(i), j(j) { }
MatrixIterator& operator =(const MatrixIterator &iter)
{
assert(&mat == &iter.mat);
i = iter.i; j = iter.j;
return *this;
}
size_t nCols() const { return mat.front().size(); }
std::string& operator *() { return mat[i][j]; }
const std::string& operator *() const { return mat[i][j]; }
MatrixIterator& operator ++() { return *this += 1; }
MatrixIterator operator ++(int) { MatrixIterator iter(*this); ++*this; return iter; }
MatrixIterator& operator --() { return *this -= 1; }
MatrixIterator operator --(int) { MatrixIterator iter(*this); --*this; return iter; }
MatrixIterator& operator += (size_t n)
{
j += i * nCols() + n; i = j / nCols(); j %= nCols(); return *this;
}
MatrixIterator operator + (size_t n) const
{
MatrixIterator iter(*this); iter += n; return iter;
}
friend MatrixIterator operator + (size_t n, const MatrixIterator &iter)
{
MatrixIterator iter2(iter); iter2 += n; return iter2;
}
MatrixIterator& operator -= (size_t n)
{
j += i * nCols() - n; i = j / nCols(); j %= nCols();
return *this;
}
MatrixIterator operator - (size_t n) const
{
MatrixIterator iter(*this); iter -= n; return iter;
}
size_t operator - (const MatrixIterator &iter) const
{
return (i * nCols() + j) - (iter.i * iter.nCols() + iter.j);
}
std::string& operator[](size_t i) { return mat[i / nCols()][i % nCols()]; }
const std::string& operator[](size_t i) const { return mat[i / nCols()][i % nCols()]; }
bool operator == (const MatrixIterator &iter) const
{
return i == iter.i && j == iter.j;
}
bool operator != (const MatrixIterator &iter) const { return !(*this == iter); }
bool operator < (const MatrixIterator &iter) const
{
return i * nCols() + j < iter.i * iter.nCols() + iter.j;
}
bool operator > (const MatrixIterator &iter) const { return iter < *this; }
bool operator <= (const MatrixIterator &iter) const { return !(iter > *this); }
bool operator >= (const MatrixIterator &iter) const { return !(*this < iter); }
};
MatrixIterator begin(Matrix &mat) { return MatrixIterator(mat, 0, 0); }
MatrixIterator end(Matrix &mat) { return MatrixIterator(mat, mat.size(), 0); }
std::ostream& operator<<(std::ostream &out, const Matrix &mat)
{
for (const Row row : mat) {
for (const std::string elem : row) out << ' ' << elem;
out << '\n';
}
return out;
}
int main()
{
Matrix mat = {
{ "5", "2", "1" },
{ "0", "0", "2" },
{ "1", "4", "3" }
};
// print input
std::cout << "Input:\n" << mat << '\n';
// sort matrix
std::sort(begin(mat), end(mat));
// print output
std::cout << "Output:\n" << mat << '\n';
// done
return 0;
}
Output:
Input:
5 2 1
0 0 2
1 4 3
Output:
0 0 1
1 2 2
3 4 5
Life demo on coliru
Notes:
I used the descriptions on cppreference.com
C++ concepts: RandomAccessIterator
C++ concepts: BidirectionalIterator
C++ concepts: ForwardIterator
C++ concepts: Iterator
std::iterator_traits
as a "requirement-cheat-sheet" and implemented everything described there. Some of the details, I decided by guess. (Especially, concerning the typedefs I'm not quite sure how to do them correct.)
You can sort the nested vectors without extra data copying by creating a custom wrapper matrix class and define your own iterator:
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>
class MyMatrix {
public:
using DataStore = std::vector<std::vector<std::string> >;
// Note: Make sure MyMatrix DO NOT out-live its `data` argument!
MyMatrix(DataStore& data) : data_(data) {
// Check that
// 1. data.size() > 0;
// 2. data[i].size() > 0 and same for all valid i.
}
class Iterator : public std::iterator<std::random_access_iterator_tag,
std::string, int> {
public:
Iterator(DataStore& data) : data_(&data), index_(0) {}
Iterator(DataStore& data, int index) : data_(&data), index_(index) {}
Iterator(const Iterator& it) : data_(it.data_), index_(it.index_) {}
Iterator& operator=(const Iterator& it) {
data_ = it.data_;
index_ = it.index_;
}
operator bool() const {
return index_ >= 0 && index_ < data_->size() * (*data_)[0].size();
}
bool operator==(const Iterator& it) const {
return data_ == it.data_ && index_ == it.index_;
}
bool operator!=(const Iterator& it) const {
return data_ != it.data_ || index_ != it.index_;
}
Iterator& operator++() { ++index_; return *this; }
Iterator& operator--() { --index_; return *this; }
Iterator operator++(int) { return Iterator(*data_, index_++); }
Iterator operator--(int) { return Iterator(*data_, index_--); }
Iterator& operator+=(int offs) { index_ += offs; return *this; }
Iterator& operator-=(int offs) { index_ -= offs; return *this; }
Iterator operator+(int offs) { return Iterator(*data_, index_ + offs); }
Iterator operator-(int offs) { return Iterator(*data_, index_ - offs); }
int operator-(const Iterator& it) { return index_ - it.index_; }
std::string& operator*() {
return (*data_)[index_ / data_->size()][index_ % (*data_)[0].size()];
}
const std::string& operator*() const { return operator*(); }
private:
DataStore* data_;
int index_;
}; // class Iterator
Iterator iterator() { return Iterator(data_); }
Iterator begin() { return Iterator(data_, 0); }
Iterator end() { return Iterator(data_, data_.size() * data_[0].size()); }
private:
DataStore& data_;
}; // class MyMatrix
Then sort could be applied to MyMatrix as follows:
#include <iostream>
int main()
{
std::vector<std::vector<std::string> > store = {
{ "5", "2", "1" },
{ "0", "0", "2" },
{ "1", "4", "3" }
};
MyMatrix matrix(store);
for (const auto& row : store) {
for (const auto& item : row) { std::cout << item <<' '; }
std::cout <<'\n';
}
std::cout <<'\n';
std::sort(matrix.begin(), matrix.end());
for (const auto& row : store) {
for (const auto& item : row) { std::cout << item <<' '; }
std::cout <<'\n';
}
std::cout <<'\n';
}
Running the above code will result in the following output:
5 2 1
0 0 2
1 4 3
0 0 1
1 2 2
3 4 5

xutility read access violation on returning isstream with custom vector

So i have a custom made vector class with also an custom allocator:
#define _SCL_SECURE_NO_WARNINGS
#include <iostream>
#include <exception>
#include <sstream>
#include <string>
#include <iostream>
namespace mem {
template<typename T>
class allocator {
public:
//
T * allocate(int n); //allocate space for n objects of type T
void deallocate(T* p); //deallocate n objects of type T starting at p
void construct(T* p, const T& v); // construct a T with the value v in p
void destroy(T* p); // destroy the T in p
};
template<typename T> T* allocator<T>::allocate(int n) //allocate space for n objects of type T
{
T* res = (T*)malloc(sizeof(T)*n);
if (res == nullptr)
throw std::bad_alloc();
return res;
}
template<typename T> void allocator<T>::deallocate(T* p/*, int n*/) //deallocate n objects of type T starting at p
{
free(p);
}
template<typename T> void allocator<T>::construct(T* p, const T& v) // construct a T with the value v in p
{
new(p) T(v);
}
template<typename T> void allocator<T>::destroy(T* p) // destroy the T in p
{
p->~T();
}
}
namespace vec {
template<typename T, typename A = mem::allocator<T>>
class vector {
A alloc; //use allocate to handle memory for elements
int sz; //the size
T* elem; //a pointer to the elements
int space; //size + free space
public:
using size_type = unsigned long;
using value_type = T;
using iterator = T * ;
using const_iterator = const T*;
vector() :sz{ 0 }, elem{ nullptr }, space{ 0 } {}
explicit vector(int s) :sz{ s }, elem{ new T[s] }, space{ s }
{
for (int i = 0; i < sz; ++i) elem[i] = 0; // elements are initalized
}
vector(const vector& arg); //copy constructor
vector& operator =(const vector& a); //copy assignment
vector(vector&& a); //move constructor
vector& operator=(vector&& a); //move assignment
~vector() { delete[] elem; } //destructor
void reserve(int newalloc);
void resize(int newsize, T val = T()); //growth
void push_back(const T& val);
iterator begin() { return elem; }
const_iterator begin()const { return elem; }
iterator end() { return elem + sz; }
const_iterator end() const { return elem + sz; }
size_type size() { return sz; }
iterator back() { return end() - 1; }
const_iterator back() const { return end() - 1; }
};
template<typename T, typename A> vector<T, A>::vector(const vector<T, A>& a) //copy constructor
:sz{ a.sz }, elem{ new T[a.sz] }
{
copy(a.elem, a.elem + sz, elem);
}
template<typename T, typename A> vector<T, A>& vector<T, A>::operator =(const vector<T, A>& a) //copy assignment
{
if (this == &a) return *this; //return if self assignment
if (a.sz <= space) { //enough space no need for new allocation
for (int i = 0; i < a.sz; ++i) //copy elements
alloc.construct(&elem[i], a.elem[i]);
sz = a.sz;
return *this;
}
T* p = alloc.allocate(a.sz);//allocate new size
for (int i = 0; i < a.sz; ++i) //copy elements
alloc.construct(&p[i], a.elem[i]);
for (int i = 0; i < sz; ++i)
alloc.destroy(&elem[i]); //destroy
alloc.deallocate(elem);
space = sz = a.sz; //set new size
elem = p; //set new elements
return *this; //return a self reference
}
template<typename T, typename A> vector<T, A>::vector(vector<T, A>&& a) //move constructor
:sz{ a.sz }, elem{ a.elem }
{
a.sz = 0; //make a the empty vector
a.elem = nullptr;
}
template<typename T, typename A> vector<T, A>& vector<T, A>::operator=(vector<T, A>&& a) //move assignment
{
delete[] elem; //deallocate old space
elem = a.elem; //copy a's elem and sz
sz = a.sz;
a.elem = nullptr; //make a the empty vector
a.sz = 0;
return *this;
}
template<typename T, typename A> void vector<T, A>::reserve(int newalloc)
{
if (newalloc <= space) return; //never decrease allocation
T* p = alloc.allocate(newalloc); //alocate new space
for (int i = 0; i < sz; ++i)
alloc.construct(&p[i], elem[i]); //copy
for (int i = 0; i < sz; ++i)
alloc.destroy(&elem[i]); //destroy
alloc.deallocate(elem/*, space*/); //deallocate old space
elem = p;
space = newalloc;
}
template<typename T, typename A> void vector<T, A>::push_back(const T& val)
{
if (space == 0)
reserve(8);
else if (space == sz)
reserve(2 * space);
alloc.construct(&elem[sz], val); //add val at the end
++sz;
}
template<typename T, typename A> void vector<T, A>::resize(int newsize, T val)
{
reserve(newsize);
for (int i = sz; i < newsize; ++i)
alloc.construct(&elem[i], val); //construct
for (int i = newsize; i < sz; ++i)
alloc.destroy(&elem[i]); //destroy
sz = newsize;
}
template<typename T, typename A> std::ostream& operator<<(std::ostream& os, const vector<T, A>& obj) //requires Element<T> && Allocator<A>
{
for (const auto& x : obj)
os << x << ' ';
os << '\n';
return os;
}
template<typename T, typename A> std::istream& operator>>(std::istream& is, vector<T, A>& obj)
{
std::string line;
std::getline(is, line);
if (is.bad() || is.fail())
return is;
std::istringstream istr{ line };
vector<T, A> tmp;
while (true) {
T tmp_in = T();
istr >> tmp_in;
if (istr.fail()) {
istr.clear();
std::string invalid;
istr >> invalid;
continue;
}
tmp.push_back(tmp_in);
if (istr.eof())break;
}
for (const auto& x : tmp)
obj.push_back(x);
return is; //its sends me to xutility in this step
}
}
int main()
{
//vec::vector <int> test; //input "1 2 3 4 5" works fine with cin >>test
vec::vector <std::string> test; //input "this is a test" breaks into xutility
while (true) {
std::cin >> test; //breaks into xutility
std::cout << test << '\n';
}
}
Now the following problem. I can read in vector values if the vector is vector. So adding 1 2 3 4 5 is no problem.
Also vector works fine.
If i change the container type to vector and read in "hello this is a test" via cin >> test; I get a crahs in xutility.h:
// MEMBER FUNCTIONS FOR _Container_base12
inline void _Container_base12::_Orphan_all() _NOEXCEPT
{ // orphan all iterators
#if _ITERATOR_DEBUG_LEVEL == 2
if (_Myproxy != 0) //It points on this line
{ // proxy allocated, drain it
_Lockit _Lock(_LOCK_DEBUG);
for (_Iterator_base12 **_Pnext = &_Myproxy->_Myfirstiter;
*_Pnext != 0; *_Pnext = (*_Pnext)->_Mynextiter)
(*_Pnext)->_Myproxy = 0;
_Myproxy->_Myfirstiter = 0;
}
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */
}
Visual Studio 2017 throws:
Exception thrown: read access violation.this was 0xC83FB858.
How can this header even get called and what is the meaning of it?
I really have no idea whats going on.
I replaced the custom vector with std::vector and then it also works.
edit: I minimized the code a bit and added a namespace for the vector. still the same behavior:
vec::vector<int> test;
std::cin >> test; //Ok: Example input 1 2 3 4 5
vec::vector<std::string> test;
std::cin >> test; //Mem access violation in xutility: Example input "this is a test"
The application crashes because:
The code does not use allocator consistently and ends up doing free() on memory that was allocated with new[].
The code does not maintain vector::space variable consistently.

What's wrong with my operator+ of custom Vector class? [closed]

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
I'm doing a custom Vector class for education purposes and I can't get the operator+ right. It triggers a breakpoint just after returning a value, but I don't know why, maybe the destructor or constructor, I don't know.
The rare part is, that when I change the operator+ to return T instead of Vector<T>, and returning thiscpy._els[i] the program runs fine. That's why I thought that the issue might be coming from constructor/destructor.
Anyways, here is the relevant part of Vector.h:
#include <initializer_list>
#include <functional>
typedef size_t SIZE;
template <class T>
class Vector {
private:
SIZE _sz;
T *_els;
public:
typedef std::function<void(Vector*)> sorting_function;
static const void populateVector(Vector*, const SIZE&, typename Vector<T>::sorting_function, const bool& sameLength = false);
Vector(SIZE sz = 0) : _sz(sz), _els(nullptr) {}
Vector(SIZE, const T&);
Vector(std::initializer_list<T>);
Vector(const Vector&);
Vector(Vector&& vec) : _sz(vec._sz), _els(vec._els) { delete[] vec._els; }
~Vector() { delete[] _els; }
Vector& operator=(const Vector&);
Vector& operator=(Vector&&);
Vector& operator=(std::initializer_list<T>);
Vector operator+(const Vector&);
SIZE size() const { return _sz; }
T* elems() const { return _els; }
int *begin() { return &_els[0]; } // for (auto i : Vector) {}
int *end() { return &_els[_sz]; } //
};
And here my relevant part Vector.cpp:
#include <stdexcept>
#include "Vector.h"
template <class T>
Vector<T>::Vector(const Vector& vec) {
cout << "Vector initializer" << endl;
if (this != &vec) {
populateVector(this, vec._sz, [&](Vector<T>* obj) {
for (SIZE i = 0; i < vec._sz; i++)
obj->_els[i] = vec._els[i];
});
}
}
template <class T>
Vector<T>& Vector<T>::operator=(const Vector<T>& vec)
{
cout << "Operator = const" << endl;
populateVector(this, vec._sz, [&](Vector<T>* obj) {
for (SIZE i = 0; i < vec._sz; i++)
obj->_els[i] = vec._els[i];
}, true);
return *this;
}
template <class T>
Vector<T>& Vector<T>::operator=(Vector<T>&& vec)
{
cout << "Operator = move" << endl;
populateVector(this, vec._sz, [&](Vector<T>* obj) {
for (SIZE i = 0; i < vec._sz; i++)
obj->_els[i] = vec._els[i];
});
delete[] vec._els;
return *this;
}
template <class T>
Vector<T>& Vector<T>::operator=(std::initializer_list<T> list)
{
populateVector(this, list.size(), [&](Vector<T>* obj) {
SIZE i = 0;
for (T elem : list)
obj->_els[i++] = elem;
});
return *this;
}
template <class T>
Vector<T> Vector<T>::operator+(const Vector<T>& vec)
{
cout << "Operator + const" << endl;
Vector<T> thiscpy(*this);
if (_sz != vec._sz) throw std::runtime_error("Vector size mismatch");
for (SIZE i = 0; i < _sz; i++)
thiscpy._els[i] += vec._els[i];
return thiscpy;
}
template <class T>
const void Vector<T>::populateVector(Vector<T>* obj, const SIZE& newsize, typename Vector<T>::sorting_function repopf, const bool& sameLength = false)
{
cout << "Pupulate vector" << endl;
if (sameLength && (obj->_sz != newsize)) throw std::runtime_error("Incompatible vector length");
obj->_sz = newsize;
try
{
if (obj->_els != nullptr) delete[] obj->_els;
obj->_els = new T[newsize];
repopf(obj);
}
catch (const std::exception& e)
{
obj->_sz = 0;
obj->_els = nullptr;
throw std::runtime_error("Couldn't populate vector");
}
}
And main.cpp:
int main() {
Vector<int> v1{ 1,2,3,4 }; //Vector<T>::Vector(std::initializer_list<T>);
Vector<int> v2{ 2,4,8,16 }; //Vector<T>::Vector(std::initializer_list<T>);
try
{
cout << "----------" << endl;
v1 + v2; //Triggers breakpoint
cout << "----------" << endl;
cout << "done" << endl;
}
catch (const std::exception& e)
{
cout << e.what() << endl;
}
cin.get();
return 0;
}
And the output of the program:
Pupulate vector
Pupulate vector
----------
Operator + const
Vector initializer
Pupulate vector
Your copy constructor never initializes els prior to calling populateVector, so it might not be nullptr (it also might be) and you're calling delete[] on whatever the content of the member pointer is. This can lead to undefined behavior.