"No viable overloaded =" nullptr - c++

I have just started with C++ and am stuck on the move constructor. Here is my .cpp:
SimpleMatrix::SimpleMatrix(SimpleMatrix &&other_mat) {
cols = other_mat.cols;
rows = other_mat.rows;
data_ = other_mat.data_;
other_mat.cols = 0;
other_mat.rows = 0;
other_mat.data_ = nullptr; // <- Error here
}
I got No viable overloaded = error at other_mat.data_ = nullptr. What went wrong? Is it the way I initialize the matrix?
Here is the relevant parts in .hpp file:
class SimpleMatrix {
public:
SimpleMatrix(std::size_t nrows, std::size_t ncols);
SimpleMatrix(std::initializer_list<std::initializer_list<double>> data);
SimpleMatrix(SimpleMatrix&& other_mat);
SimpleMatrix& operator=(SimpleMatrix&& other_mat);
private:
std::vector<std::vector<double> > data_;
int rows, cols;
};

data_ is a vector non-pointer object, and nullptr is to initialize a pointer to be a null pointer.
You can't assign non-pointer variables to be null pointers. And C++ doesn't have any concept of null values or objects.
If you want the vector to be properly initialized I suggest you add a constructor initializer list:
SimpleMatrix::SimpleMatrix(SimpleMatrix &&other_mat)
: data_(std::move(other_mat.data_)) // Move the data from the other vector
, rows(other_mat.rows)
, cols(other_mat.cols)
{
// Clear the other matrix rows and cols
other_mat.rows = 0;
other_mat.cols = 0;
}
Or, you could rely on the rule of zero and let the compiler-generated constructors handle everything for you, which in this case it should do properly:
class SimpleMatrix {
public:
SimpleMatrix(SimpleMatrix &&) = default;
// ...
};

Related

Unable to assign a nullptr in a forwarding reference after using the object for initializing inside move constructor

I am trying to get used to the move constructor and in one of tutorials it was told that it is always a good practice to initialize the original refence to the nullptr after copying the content using a forwarding reference.
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
class Matrix{
std::vector<std::vector<T>> data;
public :
Matrix(const std::vector<std::vector<T>>& vector2D){ //Copy constructor for deep copy
// Put some error handling to check the validity of vector2D
std::cout<<"Copy Constructor Called ...\n";
__uint32_t numRow = vector2D.size();
__uint32_t numColumn = vector2D[0].size();
data.resize(numRow,std::vector<T>(numColumn));
for(auto row = 0u;row < numRow; ++row){
for(auto column = 0u; column < numColumn; ++column){
data[row][column] = vector2D[row][column];
}
}
}
Matrix(std::vector<std::vector<T>>&& vector2D){ //Move constructor for shallow copy
// Put some error handling to check the validity of vector2D
std::cout<<"Move Constructor Called ...\n";
data = vector2D;
//vector2D = nullptr; // we should assign the original reference to null in my knowledge
}
void displayVector(){
__uint32_t numRow = data.size();
__uint32_t numColumn = data[0].size();
for(auto row = 0u;row < numRow; ++row){
for(auto column = 0u; column < numColumn; ++column){
std::cout<<data[row][column]<<"\t";
}std::cout<<std::endl;
}
}
Matrix operator+ (const Matrix& rhs){
// Have to complete
return data;
}
Matrix operator* (const Matrix& rhs){
// Have to complete
return data;
}
};
int main() {
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
//Matrix<int> m1(std::vector<std::vector<int>>{{1,2},{3,4}});
Matrix<int> m1({{1,2},{3,4}});
m1.displayVector();
std::vector<std::vector<int>> myVector{{5,6},{7,8}};
Matrix<int> m2(myVector);
m2.displayVector();
return 0;
}
But, when I am attempting to put nullptr inside vector2D inside the move constructor the compiler is complaining saying
no known conversion for argument 1 from std::nullptr_t to std::initializer_list of std::vector.
What are a few possibly correct ways to do such an initialization.
Two things here:
Matrix(std::vector<std::vector<T>>&& vector2D){ //Move constructor for shallow copy
// Put some error handling to check the validity of vector2D
std::cout<<"Move Constructor Called ...\n";
data = vector2D;
//vector2D = nullptr; // we should assign the original reference to null in my knowledge
}
1) you should move the received vector, to invoke vectors move assignment operator:
data = std::move(vector2D);
2) no need to manually set the vector to nullptr, it's state is already properly set.
The vector you move from is left in an "unknown, but valid state", so you can do with it anything that does not assume precondition (reasign, check size, check for emptiness, etc., you can't however expect it to have valid values inside).
As the other answer mentioned, you should also directly initialize the data, instead of doing it in the constructor body, so finally the constructor should be implemented this way probably:
Matrix(std::vector<std::vector<T>>&& vector2D) : data(std::move(vector2D)) {}
You should be writing that:
// Not a move constructor, that would be `Matrix(Matrix&&)`
Matrix(std::vector<std::vector<T>>&& vector2D) : data(std::move(vector2D)) {
std::cout<<"Move non-Constructor Called ...\n";
}
Vectors cannot be nullptr, but they can be empty - data(std::move(vector2D)) will empty the original vector and move the contents to data.

Deep copy in a move constructor

I am new to C++11 so i still strugle with its concepts.
Here's my problem :
I have a matrix class :
class matrix
{
private:
double** data;
size_t number_lines;
size_t number_columns;
size_t capacity_lines;
size_t capacity_columns;
public:
....
}
and i've provided a copy constructor, a move constructor...
I've overloaded the multiplication operator *(double x) to multiply matrix elements by the scalar x and return the multiplied matrix.
Here's the code :
matrix matrix::operator*(double lambda)
{
double** aux_data = new double*[number_lines];
for (size_t i = 0; i < number_lines; i++)
{
aux_data[i] = new double[number_columns];
for (size_t j = 0; j < number_columns; j++)
aux_data[i][j] = lambda*data[i][j];
}
return matrix(aux_data, number_lines, number_columns);
}
the return of the function is an rvalue reference so it invokes the move constructor. Here's the code of the move constructor :
matrix::matrix(const matrix&& moved_copy)
{
if (this != &moved_copy)
{
number_columns = moved_copy.number_columns;
number_lines = moved_copy.number_lines;
data = moved_copy.data;
}
}
The problem with this move constructor is that it performs a shallow copy and not a deep copy (like every move constructor i guess, otherwise what's the point of this move constructor) so the member data points to the object pointed by moved_copy.data, but this object is local to the operator *=() function so when the operator goes out of scope the object is gone and i have a dangling pointer. So my question is : should i perform a deep copy in the move constructor or is there way of solving this problem without doing so ?
Thank you.
No, you shouldn't make a deep copy in a move constructor. The whole point of a move constructor is to take ownership of some resource that's expensive to copy.
In this case, ownership of your data pointer can be transferred from an existing matrix to the newly constructed matrix object. But the idea is to transfer ownership, to the new object, not to share ownership with the new object. In this case that just means setting moved_copy.data to nullptr, that way it won't delete your data when it's destroyed.
matrix::matrix(matrix&& moved_copy)
{
number_columns = moved_copy.number_columns;
number_lines = moved_copy.number_lines;
data = moved_copy.data;
moved_copy.data = nullptr;
}
Notice that I also removed your if guard: there's no way to construct an object from itself, so that's not really needed for a move constructor (it can be useful for a move assignment operator though).
I also removed the const from moved_copy. Move constructors need to modify the state of the moved-from object to take ownership of its resources, so const cant' be used.
Edit: It is actually possible to construct an object from itself, but it's not something that you really need to guard against.
The problem with this move constructor is that the data member has the same value on both objects after the move, such that when the first object is deleted, the second has a pointer to deleted memory.
Change the move constructor to:
matrix::matrix(matrix&& moved_copy)
{
if (this != &moved_copy)
{
number_columns = moved_copy.number_columns;
number_lines = moved_copy.number_lines;
data = moved_copy.data;
moved_copy.number_columns = 0;
moved_copy.number_lines = 0;
moved_copy.data = nullptr;
}
}
The check if (this != &moved_copy) could be omitted, because an object is normally not constructed by moving from itself.
No you should not perform a deep copy in the move constructor. Otherwise you don't gain anything and the notion of a move constructor is broken:
matrix::matrix(matrix&& moved_copy)
: data(moved_copy.data),
number_rows(moved_copy.number_rows),
number_columns(moved_copy.number_columns),
capacity_rows(moved_copy.capacity_rows),
capacity_columns(moved_copy.capacity_columns) {
moved_copy.data = nullptr;
}
Furthermore, avoid to define binary operators as member functions because you're breaking the mathematical property of commutativity. That is, although:
matrix M;
...
matrix K = m * 2.0;
will work. The following won't:
matrix M;
...
matrix K = 2.0 * m;
Prefer to define binary operators as free functions.
matrix operator*(matrix const &m, double lambda) {
matrix out(m.aux_data, m.number_rows, m.number_columns);
...
return out;
}
matrix operator*(double lambda, matrix const &m) {
return m * lambda;
}
I am new to C++11.
So you won't mind me suggesting that you implement your matrix in terms of std::vector, as then all your move concerns are solved for you:
Here's the beginning of one implementation:
#include <vector>
#include <cstddef>
#include <iostream>
class matrix
{
private:
std::vector<double> storage_;
std::size_t row_capacity_;
std::size_t rows_;
std::size_t cols_;
std::size_t get_location(std::size_t row, std::size_t col) const
{
return row * row_capacity_ + col;
}
public:
matrix(std::size_t rows, std::size_t cols, std::size_t row_capacity, std::size_t col_capacity)
: storage_(row_capacity * col_capacity)
, row_capacity_(row_capacity)
, rows_(rows)
, cols_(cols) {}
matrix(std::size_t rows, std::size_t cols)
: matrix(rows, cols, rows, cols) {}
//
// note that all move/copy operations are automatically generated.
// "The rule of none"
//
std::size_t get_rows() const { return rows_; }
std::size_t get_cols() const { return cols_; }
std::size_t get_capacity_rows() const { return row_capacity_; }
std::size_t get_capacity_cols() const { return storage_.capacity() / row_capacity_; }
double& at(std::size_t row, std::size_t col)
{
return storage_[get_location(row, col)];
}
double const& at(std::size_t row, std::size_t col) const
{
return storage_[get_location(row, col)];
}
};
int main()
{
auto m = matrix(3, 3);
m.at(1, 1) = 2;
std::cout << m.at(1, 1) << std::endl;
std::cout << m.get_cols() << std::endl;
std::cout << m.get_rows() << std::endl;
std::cout << m.get_capacity_cols() << std::endl;
std::cout << m.get_capacity_rows() << std::endl;
}

Construct object, where one of its properties depends on another. In C++

Beginner in C++
I have a class, say
class A
{
public:
int N;
double .....
};
But I would like the ..... to define a matrix of size depending on N. In case that changes the approach, it is a non-identical function of N and not just N itself, say N^3+1.
In case that is the approach, I have never written a constructor of an object in C++. Therefore, if this is the approach could you please give some detail. I don't understand how it might work. When the class is instanciated, maybe the property N hasn't been even initialized.
I am not clear how to get a matrix or array (I am still not clear of the basic data types of C++) of size determined in execution.
Edit: The value of N is determined later in the code. It is something like:
A InstanceOfA; //The variable InstanceOfA is declared of type A.
...
Some other stuff happens, e.g. other properties of InstanceOfA are initialized
and some of the functions are used. And then:
...
A.setN(4);
I didn't understand from the answer below. Would I need to do
A InstanceOfA(4);
?
You can use std::vector
class A
{
public:
int N; // you should use int for size
double std::vector<std::vector<double>> matrix; //define the matrix
//initialize it in the constructor
A( int size ):N(size), matrix(size*3+3)// or you can use any expression that evaluates an integral value
{
//you can initialize the values in matrix here
}
};
Note
the expression matrix(size*3+3) initializes the matrix such that, there are size*3+3 rows, the number of columns in each row are not specified yet. You can also specify column sizes in the constructor like
for( int i=0;i< N*3+3; ++i) //for each row
{
matrix[i].resize(N*2);// resize each col to hold N*2 cells,
}
Edit
As per the modification in question, you can then leave the constructor empty (or initialize any other members), and provide a setSize method in class A, which will later initialize the size.
void setSize(int size){
N= size;
matrix.resize( size*3+3);
for( int i=0;i< N*3+3; ++i) //for each row
{
matrix[i].resize(N*2);// resize each col to hold N*2 cells,
}
}
Then you can use it like:
A instanceOfA;
//other code
//
instanceOfA.setSize(N);
You can use an std::vector<std::vector<double>> to capture the matrix. Also, change the type of N to int.
class A
{
public:
int N;
std::vector<std::vector<double>> matrix;
};
Define a constructor and initialize the data in the constructor.
class A
{
public:
A(int n) : N(n)
{
int matrixSize = N*N*N+1;
for (int i = 0; i < matrixSize; ++i )
{
matrix.push_back(std::vecotr<double>(matrixSize));
}
}
double N;
std::vector<std::vector<double>> matrix;
};
One possible way is to do it with a pointer. If you only allocate your array in constructor and its size will not change during the lifetime of your object, that could be done in this way:
class A
{
public:
double N;
double* arr;
A(double aN):N(aN)
{ arr = new double[3*N+1]; // allocate your array in constructor
... // do whatever else you need to initialize your object
}
...
~A() { delete[] arr;} // free it in destructor
...
}
See also the tutorial on Dynamic Memory.
You will then instantiate your class in one of two ways:
A a(aN);
// this object will be automatically destroyed when it gets out of scope, for example at the end of the function where it was created
A* a = new A(aN);
// this object will have to be deleted by yourself when it's no longer needed:
...
delete a;
If you don't know N at the moment when you create your object, you can postpone the allocation :
class A
{
public:
double N;
double* arr = NULL;
A() { ... } // do whatever you need in your constructor
setN(double aN)
{
N = aN;
arr = new double[3*N+1]; // allocate your array
}
...
~A() { if(arr) delete[] arr;} // free your array in destructor if needed
...
}
then you can call your object as:
A a;

Move constructor for a custom container?

is the move constructor for a class that holds a dynamically allocated array supposed to delete it? For instance I have:
template<typename T>
class MyVector
{
public:
MyVector()
{
data = new T[32];
capacity = 32;
size = 0;
}
MyVector(const MyVector<T>& o) //The basic copy constructor
{
capacity = o.capacity;
size = o.size;
data = new T[capacity];
for(int i = 0; i < _size; i++)
{
data[i] = o.data[i];
}
}
MyVector(const MyVector<T>&& o) //The move constructor
{
//What goes here?
}
private:
T* data;
unsigned int size;
unsigned int capacity;
};
I understand the move constructor is called when I do something like:
MyVector A;
A = MyVector(); //The one on the right gets a move constructor called?
So is it supposed to be identical to the copy constructor?
is the move constructor for a class that holds a dynamically allocated array supposed to delete it? For instance I have:
There is nothing to delete. The object is being constructed after all. All it should do is take the resources from the object on the RHS. It should leave the RHS in a reasonable state. For example,
MyVector(MyVector<T>&& o)
{
data = o.data;
o.data = nullptr;
capacity = o.capacity;
o.capacity = 0;
size = o.size;
o.size = 0;
}
Note that, in order for a move constructor to work, the parameter cannot be const. A move constructor modifies its argument.

Copy constructor for 2d array c++

I have managed to overload the assignment operator, so I do have a workaround for this, but it would be nice to know why I couldn't get it working.
The beginning of my arr2d class looks like:
template <class type> class arr2d {
private:
type* m_ptr;
int m_nx,m_ny;
public:
arr2d(){
m_ptr = 0;
m_nx = 0;
m_ny = 0;
}
// Default constructor creates a null array
arr2d(int nx, int ny):m_nx(nx),m_ny(ny){
m_ptr = new type [nx*ny];
if ( m_ptr==0 ){cout << "\nError allocating heap memory.\n";}
}
// // Copy constructor
// arr2d(const arr2d& rhs){
// m_ptr = new type [m_nx*m_ny];
// for(int j=0;j<m_ny;j++){
// for(int i=0;i<m_nx;i++){
// m_ptr[j*m_nx+i] = rhs.m_ptr[j*m_nx+i];
// }
// }
// }
and so on,
You can see my attempted copy constructor commented out there.
Now in my main, I would like to call the copy constructor using for instance:
arr2d b=a;
Where the b array now has the same values as a. What am I doing incorrectly?
You copy constructor is not assigning the array size. It should be something like
arr2d(const arr2d& rhs) : m_nx(rhs.m_nx), m_ny(rhs.m_ny) {
...
}
In addition to initializing m_nx and m_ny as 6502 said, you still need the template argument when declaring b. E.g.
arr2d<int> b = a;