Deep copy of a matrix-like class - c++

I've got a class that shall behave like matrix.
So the usecase is something like:
Matrix matrix(10,10);
matrix[0][0]=4;
//set the values for the rest of the matrix
cout<<matrix[1][2]<<endl;
code:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <sstream>
using namespace std;
class Matrix {
public:
Matrix(int x, int y);
class Proxy {
public:
Proxy(int* _array) : _array(_array) {
}
int &operator[](int index) const {
return _array[index];
}
private:
int* _array;
};
Proxy operator[](int index) const {
return Proxy(_arrayofarrays[index]);
}
Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}
const Matrix& operator=(const Matrix& othersales);
private:
int** _arrayofarrays;
int x, y;
};
Matrix::Matrix(int x, int y) {
_arrayofarrays = new int*[x];
for (int i = 0; i < x; ++i)
_arrayofarrays[i] = new int[y];
}
const Matrix& Matrix::operator=(const Matrix& othermatrix) {
new (this) Matrix(x, y);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
_arrayofarrays[i][j] = othermatrix._arrayofarrays[i][j];
return *this;
}
int main() {
Matrix a(2, 3);
a[0][0] = 1;
a[0][1] = 2;
a[0][2] = 3;
a[1][0] = 4;
a[1][1] = 5;
a[1][2] = 6;
cout << a[1][2] << endl;
//prints out 6
const Matrix b = a;
cout << b[1][2] << endl;
a[1][2] = 3;
cout << a[1][2] << endl;
// prints out 3
cout << b[1][2] << endl;
// prints out 3 as well
}
By calling const Matrix b = a; I want to create new instance of Matrix, that will have the same values as a has in that moment. Nevertheless b is being affected by changing the values in a. So if I change some value in a, then it changes in b as well. And I don't want it to behave like this.
So I need to create a copy of b that would not be affected by a itself.
Those might be stupid question, but for me, as a java guy and a C++ newbie are all those stuff really confusing, so thanks for any helpful advices...

There are a few issues with your implementation. The simple one is the error you are getting...
In your Matrix class, operator[] is a non-const member function, which means that it can only be executed on non-const objects. Your operator= takes the right hand side object by const &, and thus you cannot call operator[] on it. The issue here is that you are not offering an implementation of operator[] that promises not to modify the object, once you add that to your type it should compile.
More important than that is the fact that you are leaking memory. When you call operator= on an object you are creating a different Matrix in place, without previously releasing the memory that it held. That is a memory leak.
The implementation of operator= is also not thread-safe. If allocation of memory for any of the internal arrays fails and throws an exception you are leaving your object in a state that is neither the original one nor a valid state. This is bad in itself.
Related to the previous, in as much as correcting one probably leads to the other, your implementation of operator= is not safe if there is aliasing, that is, it fails if you self-assign. The first line will leak the memory and create the new buffers, and from there on you will copy the new buffer into itself, loosing the original information.
Finally, the implementation of the type could be improved if you drop the requirement of using operator[] and use instead operator() with the two indices. User code will have to be adapted (and look less like a bidimensional array) but it provides a bit more freedom of representation (you can store the information internally in any way you want). At the same time, there is no need to allocate an array of pointers and then N arrays of int. You can perform a single memory allocation of NxM ints and do pointer arithmetic to address each location (this is independent of the use of operator[]/operator()), which will reduce the memory footprint and make the layout more compact, improving cache performance (not to mention reducing the number of dynamic allocations by a factor of M)
By calling const Matrix b = a; I want to create new instance of Matrix, that will have the same values of a in that moment. Nevertheless b is being affected by changing the values in a.
Well, this is yet another issue I missed in the first read. The expression const Matrix b = a; does not involve operator=, but rather the copy constructor. Another thing to google: Rule of the Three (basically, if you implement one of copy-constructor, assignment or destructor manually, you probably want to implement all three). Without defining your own copy constructor the compiler will implicitly define one for you that does a shallow copy (i.e. copies the pointers stored in Matrix but does not allocate memory for it). After the copy is made both Matrix share the same memory, and if your destructor releases the memory, you will run into Undefined Behavior when the second destructor runs and tries to delete [] the already deleted memory.

Related

C++ my copy constructor fails to move the memory to a new area

So I've recently started to work on getting my own vector class working and I'm a little bit stuck on my copy constructor. I'm obviously rather new to c++ and was hoping the good guys at stack overflow could help me out a bit. So I got this copy constructor which copies the actual ptr being used, the end index of the ptr (the elements the user can use) and the actual capacity/reserved memory the ptr has, plus the size of the used memory.
vector(const vector &other) : storage(other.storage), capacity(other.capacity),
endIndex(other.endIndex), m_size(other.m_size)
{
T* storage = new T[capacity];
memcpy(storage, other.storage, sizeof(T) * capacity);
}
The issue is that while it seemingly copies the information successfully, if one of the objects run out of scope, the information, or at least some of it gets deleted. If I also do a push_back on one of the vector objects, it happens on both of them. So it's fairly safe to say that they share address for their ptr. For example if I run this code in my main function
int main()
{
vector<int> vec;
vec.push_back(5);
vec.push_back(55);
vec.push_back(500);
vector<int> vec1 = vec;
for (int i = 0; i < vec1.size(); i++)
{
std::cout << vec1[i] << std::endl;
}
return 0;
}
I will get this error message
5
55
500
free(): double free detected in tcache 2
Aborted (core dumped)
I'm assuming this is because the ptr gets deleted while going through the loop and it in turn crashes the program in a nice fashion. Another example of the push_back is
int main()
{
vector<int> vec;
vec.push_back(5);
vec.push_back(55);
vec.push_back(500);
vector<int> vec1 = vec;
vec.push_back(55);
for (int i = 0; i < vec1.size() + 1; i++)
{
std::cout << vec1[i] << std::endl;
}
return 0;
}
Where you can obviously see that i actually push_back on the original vector object and not the new one, i even have to increase the for-loops scope to be able to see the object on the new vector, hinting at the size integer in the new object is unchanged from before. Output of this code is:
5
55
500
55
free(): double free detected in tcache 2
Aborted (core dumped)
I don't expect anyone to take time out of their day to debug my code, I don't want that. I'm merely asking for a pair of professional eyes to glance over it and help a newbie out. Thanks in advance.
There are multiple issues with your code.
The first and foremost one is this:
T* storage = new T[capacity];
That storage is not the same as the member variable storage. It is a local variable that just happens to have the same name. Once the copy constructor is complete, you haven't done anything except leak memory.
In addition, you have this:
vector(const vector &other) : storage(other.storage),
This assigns the pointer other.storage to this. This is actually where the double-free comes from. You are doing a shallow copy, thus when this and other are destroyed, the same pointer value will be used in the call to delete [] in the destructor.
The third issue is this:
memcpy(storage, other.storage, sizeof(T) * capacity);
This will not work for types that are not trivially-copyable. Let's say you fix all the issues except this one. This code will fail miserably:
vector<std::string> s;
and the reason is that you can't use memcpy to copy std::string objects, since std::string is not trivially-copyable.
The fix is to use std::copy, not memcpy, since std::copy is (should be) smart enough to either do a memcpy for trivially-copyable types, or a plain loop for non trivially-copyable types.
The last issue is your naming of the class vector. Note that there already is a std::vector in C++. Either change the name to something else, or place your class in its own namespace so that a name clash will not occur if you happen to #include <vector> somewhere.
Putting that all together, you will have this (not compiled, forgive any syntax errors):
#include <algorithm>
namespace myVector
{
template <typename T>
class vector
{
private:
// your member variables
public:
//...
vector(const vector &other) : capacity(other.capacity),
endIndex(other.endIndex), m_size(other.m_size)
{
storage = new T[capacity]();
std::copy(other.storage, other.storage + other.m_size, storage);
}
vector& operator=(const vector& other)
{
// see later
}
~vector()
{
delete [] storage;
}
//...
};
}
Then the main could be this:
#include <myvector>
int main()
{
myVector::vector<int> vec;
vec.push_back(5);
vec.push_back(55);
vec.push_back(500);
myVector::vector<int> vec1 = vec;
for (int i = 0; i < vec1.size(); i++)
{
std::cout << vec1[i] << std::endl;
}
return 0;
}
Once this is all done and corrected, to complete the rule of 3, the assignment operator can be simply this:
vector& operator=(const vector& other)
{
if ( &other != this )
{
vector temp(other);
std::swap(temp.capacity, capacity);
std::swap(temp.m_size, m_size);
std::swap(temp.endIndex, endIndex);
std::swap(temp.storage, storage);
}
return *this;
}
The above is using the copy/swap idiom
The problem is simple, but hard to see in your own code since you know what you want it to do. You could track it down by stepping through in a debugger and examining the value and address of storage scrupulously on every line.
Seriously, try doing that first.
OK, so here is it:
vector(const vector &other)
: storage(other.storage) // 1. copy the pointer, so this->storage is shared
, capacity(other.capacity)
, endIndex(other.endIndex)
, m_size(other.m_size)
{
// 2. declare a local variable called storage which shadows this->storage
T* storage = new T[capacity];
memcpy(storage, other.storage, sizeof(T) * capacity);
}
You do not want the storage to be shared, so you should never initialize storage(other.storage). There is literally no reason to do this in your code. If you just initialize it to nullptr you would have realized very quickly that the local variable in the constructor body was wrong.
Simply removing the T* from T* storage = ... will fix your immediate problem. All the other suggestions about using std::copy instead of memcpy, and how better to structure your code are good ones, and you should do those too.

Unwanted value changes in 1D and 2D arrays returning a value from a function in c++ code

I have a multi-file program that reads data from a file and stores the values in various arrays. The size of the arrays is not known during the compiling. After the values are stored, I use another function to determine the maximum and minimum of each array and return the max/min. Before the "return maximum" statement, the values in the array are correct. After "return maximum", the values are changed or erased.
Here is some of the code including one of the 2D arrays and one of the 1D arrays (there are a few more of those but I removed them so there's less code for you to look at)
**EDITED:
FunctionValues.h: ** removed destructor block
class FunctionValues
{
//define variables, set up arrays of unknown size
public:
float **xvel;
int *imax;
int vessels;
int tot_gridpt;
public:
//Constructor -- initialization of an object performed here
FunctionValues(): xvel(NULL), imax(NULL) {}
//Destructor
~FunctionValues() {
}
void read_function(string filename);
};
FunctionValues.cpp: (this reads a file with some imax values, vessel numbers and velocities and stores them in the appropriate arrays, the other includes are also there) All the arrays made are stored in FunctionValues myval object
#include "FunctionValues.h"
using namespace std;
void FunctionValues::read_function(string filename)
{
std::ifstream myfile(filename.c_str());
//acquire variables
myfile >> vessels; //number of vessels
imax = new int[vessels];
//... code reading the file and storing them, then imax and some other values are multiplied to get int tot_gridpt
xvel = new float *[vessels];
for (int i = 0; i < vessels; i++)
{
xvel[i] = new float[tot_gridpt];
}
//arrays filled
for (int i = 0; i < limiter; i++)
{
myfile >> xvel[count][i];
}
}
Gridpts.cpp: ** range() arguments and parameters
#include "FunctionValues.h"
#include "Gridpts.h"
using namespace std;
// forward declarations
float range(float **velocities, const FunctionValues *myval, int num);
void Gridpts::create_grid(FunctionValues *myval, int ptsnum)
{
//find range, 1 for max, 0 for min from smooth wall simulation results rounded to the nearest integer
float maximum = range(myval->xvel, &myval, 1);
float minimum = range(myval->xvel, &myval, 0);
}
range.cpp: ** arguments changed to pass by pointer
float range(float **velocities, const FunctionValues *myval, int num)
{
if (num == 1)
{
float maximum = 0;
for (int round = 0; round < myval->vessels; round++)
{
for (int count = 0; count < myval->tot_gridpt; count++)
{
if (velocities[round][count] > maximum)
{
maximum = velocities[round][count];
}
}
}
maximum = ceil(maximum);
return maximum;
}
main.cpp:
corner_pts.create_grid(&myval, ptsnum);
This is where the error occurs. cout << "CHECKPOINT: " << myval.xvel[0][0] before "return maximum;" gives -0.39032 which is correct. After "return maximum", causes nothing to be printed and then the program crashes when trying run range() again using the xvel array. Similarly for myval.imax[0].
I apologize for copying in so much code. I tried to only include the essential to what is happening with the array. I have only started programming for about a month so I'm sure this is not the most efficient way to write code but I would greatly appreciate any insight as to why the arrays are being changed after returning a float. Thank you in advance for your time. (And if I have broken any rule about posting format, please let me know!)
So your program crashes when you call range() the second time. Therefore, your issue is most likely there.
Your program is crashing because you are taking your FunctionValues parameter by value, which is then destroyed at the end of the scope of the function, since it is local to the function.
// issue with myval being taken as a copy
float range(float **velocities, FunctionValues myval, int num)
{
//...
} // destructor for local function arguments are called, including myval's destructor
Explanation
Your function parameter FunctionValues myval is taken by copy. Since you have no copy constructor defined, this means that the default copy behavior is used. The default copy behavior simply copies the object data from the supplied argument at the call site.
For pointers, since they hold addresses, this means that you are copying the addresses of those pointers into an object local to the range() function.\
Since myval is local to the range() function, its destructor is called at the end of the scope of the function. You are left with dangling pointers; pointers holding the memory addresses of memory that you have already given back to the free store.
Simplified example of your error:
#include <iostream>
class X
{
public:
X() : p{ new int{ 0 } }
{
}
~X()
{
std::cout << "Deleting!" << std::endl; // A
delete p; // B
}
private:
int* p;
};
void func(X param_by_value) // C
{
// ...
}
int main()
{
X x; // D
func(x); // E
func(x); // F
}
You have variable x (D). You use it to call the function func() (E).
func() takes a parameter of type X by value, for which the variable name is param_by_value (C).
The data of x is copied onto param_by_value. Since param_by_value is local to func(), its destructor is called at the end of func().
Both x and param_by_value have an int* data member called p that holds the same address, because of 3..
When param_by_value's destructor is called, we call delete on param_by_value's p (B), but x's p still holds the address that was deleted.
You call func() again, this time the same steps are repeated. x is copied onto param_by_value. However, this time around, you try to use memory that has been given back to the free store (by calling delete on the address) and (luckily) get an error. Worse yet, when main() exits, it will attempt to call x's destructor again.
You need to do some research into function parameters in C++. Passing by value, passing by reference, passing by pointer, and all of those combined with const.
As user #MichaelBurr points out, you should also look up the rule of three (and rule of five).
I'm just wondering why you opted not to use functionality like std::max/min_element in and std::valarray/vector to allocate a contiguous chunk of memory?
Worse case scenario, if you're a fan of the explicit nature of 2d arrays x[a][b] you could create a basic matrix:
template <typename T>
class Matrix {
public:
Matrix(std::valarray<int>& dims) : dims(dims) {}
Matrix(std::valarray<int>& dims, std::valarray<T>& data) : dims(dims), data(data) {}
std::Matrix<T> Matrix::operator[](int i) {
auto newDims = std::valarray<int>(dims[1], dims.size() - 1);
auto stride = std::accumulate(std::begin(newDims), std::begin(newDims) + newDims.size(), 1, [](int a, int b){ return a * b; })
auto newData = std::valarray<T>(data[i * stride], data.size() - (i * stride));
return Matrix<T>(newDims, newData);
}
protected:
std::valarray<T> data;
std::valarray<int> dims;
}
I think more reliance on the standard libraries for their correctness will likely solve any memory access/integrity issues.

Exploiting fact that elements of vector are stored in heap?

Lets say you have something like this
#include <iostream>
#include <vector>
using namespace std;
vector<int> test()
{
vector <int> x(1000);
for (int i = 0; i < 1000; i++)
{
x[i] = 12345;
}
return x;
}
int main(int argc, const char * argv[])
{
vector<int> a = test();
return 0;
}
where within a function you create a vector and fill it with some elements (in this case I chose 12345 but they won't necessarily all be the same).
I have read that the elements of the vector are stored on the heap whereas the reference and header data are stored on the stack. In the above code, when x is returned a copy-constructor must be called, and this takes O(n) time to copy all the elements into a new vector.
However, is it possible to take advantage of the fact that all the elements already exist on the heap in order to just return something like a pointer to those elements and later just create a vector that uses that pointer in order to point to those exact same elements — thus avoiding the need to make a copy all the elements of a vector?
The compiler does this for you, freeing you up to write nice , easy-to-read code, rather than mangling your code for the sake of optimization.
When you return a value for a function, the compiler is allowed to elide the return value object. The net effect is that the compiler can just create x in the actual memory location of a.
Even if it doesn't do this (e.g. it chooses not to for some reason, or you disable it by a compiler switch), then there is still the possibility of a move.
When a move happens, the vector will just transfer ownership of the pointer from x to the return value, and then from the return value to a. This leaves x etc. as an empty vector, which is then correctly destroyed.
You could explore this by writing a test class (instead of vector<int>) which prints something out for its default constructor, copy-constructor, and move-constructor, e.g.
#include <iostream>
struct A
{
A() { std::cout << "default\n"; }
A(A const &) { std::cout << "copy\n"; }
A(A &&) { std::cout << "move\n"; }
};
A func() { A a; return a; }
int main()
{
A b (func());
}
Output with g++:
default
Output with g++ -fno-elide-constructors:
default
move
move

dynamic arrays and operator overloading cause memory crash

To illustrate my problem I minimalize my source:
#include <iostream>
class vec{
public:
float* X;
int DIM;
vec(int dimension)
{
DIM = dimension;
X = new float[dimension];
for (int i=0;i<DIM;i++)
X[i] = (float) rand()/RAND_MAX;
}
~vec(void){
delete [] X;
}
vec operator-( vec const& rhs )
{
vec ans(DIM);
for (int i=0;i<DIM;i++)
ans.X[i] = X[i] - rhs.X[i];
return ans;
}
};
int main(){
vec A(5),B(5),C(5);
C= A-B;
return 0;
}
When I execute this program I get an error that a heap was destroyed. I am pretty sure that the destructor is my problem. In the line with C= A-B; the variable ans will be destroyed by the constructor and cannot be returned. Is that right?
If I delete the line delete [] X; everything is ok. But it won't free up the memory.
I did my homework and consult one of the most famous search engine for this problem but didn't find any answer. How can I fix it?
C = A-B calls the default copy-assignment operator (as you haven't defined one). Therefore two different objects will point to the same dynamically-allocated array.
You need to read up on the Rule of Three (in a nutshell: if you define any of the destructor, the copy constructor or the copy-assignment operator, you probably need to define them all).
But preferably, you should avoid using raw arrays entirely; use a container type that manages its own memory.

Overload operator '+' to add two arrays in C++

I want to add two arrays by simply writing:
int a[4] = {1,2,3,4};
int b[4] = {2,1,3,1};
int sum[4] = a + b;
I wrote this function but I got an error
int* operator+(const uint32& other) const{
uint32 sum[n];
for(int i=0; i<n; i++){
sum[i] = (*this[i]) + other[i];
}
return sum;
}
Could you help me on this? Thanks in advance.
Let's go through your code, piece by piece, and look at the problems:
int* operator+(const uint32& other) const{
You can't overload operators for built-in types, so this is doomed from the beginning
Even if you could do this (which you can't), it needs to take two parameters since it's non-member binary function.
uint32 sum[n];
You can't make variable-length arrays in C++ (assuming n isn't a compile-time constant) (note: G++ has some extensions that allow this, but it's non-standard C++)
for(int i=0; i<n; i++){
sum[i] = (*this[i]) + other[i];
There's no this pointer to begin with in this code (it's not a member function)...
const uint32& other is not an array/pointer to an array. It's a single reference to a single uint32. That means that other in this code is not an array/pointer to an array, and so you cannot do other[i] (it's like trying to do int x = 3; x[4] = 13;, which makes no sense).
}
return sum;
You're returning a pointer to a locally allocated array, which means this will result in undefined behavior, as the memory associated with sum is going to get annihilated when this function returns.
}
This is probably wrong, but it appears to work (C++11):
#include <iostream>
#include <array>
using namespace std;
template <class T>
T operator+(const T& a1, const T& a2)
{
T a;
for (typename T::size_type i = 0; i < a1.size(); i++)
a[i] = a1[i] + a2[i];
return a;
}
int main()
{
array<int,5> a1 = { 1, 2, 3, 4, 5 };
array<int,5> a2 = { 2, 3, 4, 5, 6 };
array<int,5> a3 = a1 + a2;
for (int i = 0; i < 5; i++)
cout << a1[i] << '+' << a2[i] << '=' << a3[i] << ' ';
cout << endl;
return 0;
}
Output (ideone):
1+2=3 2+3=5 3+4=7 4+5=9 5+6=11
I think the issue is that you're missing a way to pass in the length of the array. You might need to do something a bit more sophisticated. Something like:
class AddingVector : public std::vector<int>
{
public:
typedef AddingVector type;
type operator+(const AddingVector& rhs, const AddingVector& lhs)
{
/* validate that they're the same size, decide how you want to handle that*/
AddingVector retVal;
AddingVector::const_iterator rIter = rhs.begin();
AddingVector::const_iterator lIter = lhs.begin();
while (rIter != rhs.end() && lIter != lhs.end()) {
retVal.push_back(*rIter + *lIter);
++rIter;
++lIter;
}
return retVal;
}
}
You cannot do that. Non-member binary operators must take two arguments (you only provided one), so you could try this:
int* operator+(const uint32& a, const uint32& b)
But that can't possibly work either, since you want to add arrays, not single uint32 variables. So you would think that this would do it:
int* operator+(const uint32[] a, const uint32[] b)
or:
int* operator+(const uint32[4] a, const uint32[4] b)
But no go. It's illegal because you cannot have pointer types as both arguments in an operator overload. Additionally, at least one of the arguments must be a class type or an enum. So what you're trying to do is already impossible on at least two different levels.
It's impossible to do what you want. One correct way to go about it is to write your own class for an array that can be added to another one.
You cannot overload operators for types other than your own defined types. That is, if you create a class X, you can overload operators for X, but you cannot overload operators for arrays or pointers to fundamental types.
first is your code getting compiled properly, you have used 'n' directly in declaring array, is 'n' declared as constant..
And moreover you have taken a local variable in the function and returning it, well, this return a garbage form the stack, wat i can suggest is you malloc some memory and use it,, but again freeing it would be needed...
Hey, what you could do is,
Take a wrapper class "array"
class array
{
int *ipArr;
DWORD size;
};
then in constructor you can pass the size you want to have an array of
array(DWORD dwSize);
{
// then malloc memory of size dwSize;
}
Have an overloaded operator'+' for this class, that will have the above implementation of adding two int arrays,
Note here you will also need to overlaod the '=' assignment operator, so that our array class can you is directly..
now you can free the associated memory in the destructor
You have a few problems. The first is that you aren't passing in both arrays, and then you don't specify what n is, and the last is that you are trying to pass out a pointer to a local variable. It looks like you are trying to make a member operator of a class.
So basically you are trying to add the contents of an unspecified length array to an uninitialised array of the same length and return the stack memory.
So if you pass in pointers to the arrays and the length of the array and an output array then it would work, but you wouldn't have the syntax
sum = a + b;
it would be something like
addArray(&a, &b, &sum, 4);
To get the syntax you want you could make a class that wraps an array. But that is a much more complicated task.