I want to build my own full Vector class in C++. I started like this:
#include <iostream>
#include <initializer_list>
#define Print(x)(std::cout<< x << std::endl)
// Vector Class //
template <typename T>
class Vector
{
// Attributes
int length = 0;
T* array;
public:
// Default constructor
Vector()
: length(0), array(nullptr)
{ }
// Copy constructor
template<typename U>
Vector(const Vector<U>& other)
: Vector(other.len())
{
Print("Use Copy Constructor");
// Coppying other data to new array
array = new T[other.len()];
for (auto i=0; i < other.len(); i++)
array[i] = other[i];
}
// Move constructor
Vector(Vector<T>&& other)
: length(other.len()), array(other.array)
{
Print("Use Move Constructor");
// Deleting other array
other.length = 0;
other.array = nullptr;
}
// Constructor (does not allow uniform initialisation)
Vector(int length)
: length(length), array(new T[length])
{ }
// Constructor (with initialiser list and delegate constructor)
Vector(std::initializer_list<T> list)
: Vector((int)list.size())
{
std::uninitialized_copy(list.begin(), list.end(), array);
}
// Destructor
~Vector()
{
length = 0;
delete[] array;
array = nullptr;
}
// Function Len that returns the length
int len() const
{
return length;
}
// Operator[](int i) and its const overload
auto& operator[](int i)
{
return array[i];
}
auto& operator[](int i) const
{
return array[i];
}
// Copy assignment operator
template<typename U>
Vector& operator=(const Vector<U>& other)
{
Print("Use Copy Operator");
if (this != (Vector*)& other) {
/*
This works the same way but does not solve the problem:
Vector<typename std::common_type<T,U>::type> temp(other);
temp.swap(*this);
*/
delete[] array;
length = other.len();
array = new T[other.len()];
for (auto i = 0; i < other.len(); i++)
array[i] = other[i];
}
return *this;
}
// Move assignment opertator
Vector& operator=(Vector<T>&& other)
{
Print("Use Move Operator");
if (this != (Vector*)&other){
/*
This works the same way but does not solve the problem:
Vector<T> temp(std::move(other)); // moves the array
temp.swap(*this);
*/
delete[] array;
length = other.len();
array = other.array;
other.len() = 0;
other.array = nullptr;
}
return *this;
}
};
But if I now try to use the copy assignment operator like this:
Vector<double> double_vector = {3.4677, 3.212, 2.2, 6.3};
Vector<double> a = double_vector;
I get the following error message:
error: use of deleted function 'constexpr Vector<double>::Vector(const Vector<double>&)'
I assume that the problem lies within the copy constructor and copy assignment operator, but I sadly can't find a solution. What I find strange is that, if I comment out the move constructor and move assignment operator, the code does seem to work. This lets me think that the compiler has difficulty knowing which constructor to use. But I could also be very wrong about this.
Hope I gave enough info for an answer/push in the right direction.
A template is never a copy constructor, that is a converting constructor.
And as you have defined a bunch of other constructors, the otherwise default copy constructor will be defined as deleted.
Related
I want to implement Matrix class with the help of pointers:
class Matrix{
private:
int row;
int col;
double elem**
public:
//Default Constructor:
Matrix(int row,int col);
//Initialized list constructor:
Matrix(initializer_list<initializer_list<double>> lst);
//Destructor
~Matrix();
//Copy constructor
Matrix(const Matrix& other);
//Copy assingment
Matrix operator=(const Matrix& other);
//Move constructor
Matrix(Matrix&& other);
//Move assingment
Matrix operator=(Matrix&& other);
But I have problem with creating moving constructor and assingment:
I have found similar post(How to use move constructor with 2d array (**<type>)?) and based on that post I created my move constructor and move assingment:
//Move assingment
Matrix operator=(Matrix&& other){
for(int i = 0;i<row;++i){
delete[] elem[i];
}
delete[] elem;
elem = other.elem;
row = other.row;
col = other.col;
other.elem = nullptr;
other.row = 0;
other.col = 0;
return *this;
}
//Move constructor
Matrix::Matrix(Matrix&& other):
row{other.row},
col{other.col},
elem{other.row}
{
other.elem = nullptr;
other.row = 0;
other.col = 0;
}
But I didn't understand the logic. Why can we just assign the pointer to pointers 2d array like this: elem = other.elem; and elem{other.row}
Shouldn't we assign elements for each row separately using for loop? like elem[i] = new double[other.col] ?
Lets take it step by step:
The move assignment operator function or move constructor is called
other.elem points to some memory
With elem = other.elem you now have two pointers pointing to the same memory
With other.elem = nullptr only this->elem is pointing to that memory
It's really no different than e.g.
int a;
int b;
a = 5; // Corresponds to the initialization of other.elem
b = a; // Corresponds to elem = other.elem
a = 0; // Corresponds to other.elem = nullptr
moving means stealing.
Just snatch what other has.You make elem point to other's memory and now you own it and make other point to null.
The whole point of move is to avoid a copy, so you don't do a row wise copy.Row wise copy makes sense in copy construction and copy assignment when you want you(this) and other both to have independent resources.
I am trying to learn the new features in C++11. And I am testing the following code in XCode.
#include <iostream>
#include <string>
#include <vector>
class CClass
{
std::string s;
public:
CClass()
{
std::cout<<"Default Constructor"<<std::endl;
}
CClass(const std::string v) :s(v) {
std::cout<<"Constructor"<<std::endl;
}
CClass(const CClass& other): s(other.s) {
std::cout<<"Copy Constructor"<<std::endl;
}
CClass(CClass&& a) noexcept
{
std::cout<<"Move Constructor"<<std::endl;
s = std::move(a.s);
}
CClass& operator = (const CClass& other)noexcept
{
std::cout<<"Copy Assignment"<<std::endl;
if(this != &other)
{
s = other.s;
}
return *this;
}
CClass& operator = (CClass&& other) noexcept
{
std::cout<<"Move Assignment"<<std::endl;
if(this != &other)
{
s = std::move(other.s);
}
return *this;
}
};
int main()
{
std::vector<CClass> v;
CClass x("hello");
//v.push_back(x);
std::cout<<"--------------------"<<std::endl;
v.emplace_back("uiuiu");
std::cout<<"--------------------"<<std::endl;
}
When I uncomment the push back I get the following result:
Constructor
Copy Constructor
--------------------
Constructor
Move Constructor
--------------------
Otherwise, if I comment it, I get:
Constructor
--------------------
Constructor
--------------------
My question is why is the move constructor not being called in second case? It is only being called in the first case when vector is initially not empty.
It's because the one element in the vector needs to be moved to a new memory location. The reason why that happens is that the new size would exceed the vector capacity, so new memory with the new capacity had to be allocated for the vector.
From std::vector::emplace_back:
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.
The iterators and references are invalidated for the same reason: Because the elements are now stored in a new location in memory.
If you call reserve in the first case, you'll see that no move constructor is called:
CClass x{"hello"}; // constructor
v.reserve(2); // make space for 2 elements (you could have also used resize)
v.push_back(x); // copy constructor
v.emplace_back("uiuiu"); // constructor
I am working on an assignment that calls for the writing the function implementations of the Big 3 when constructing a class with pointers. I seem to be having trouble with the copy constructor. I think I am doing the other 2 correctly.
class RealBox
{
private:
float* m_reals; // Array of Real Numbers
int m_boxsize; // number of Real Numbers in this box
public:
// Purpose: Constructs an Real-Box
// Preconditions:
// 's' is greater than 0;
// Postconditions:
// m_reals points to a dynamically allocated array of size 's'
// all elements of m_reals[] are initiallized to 'a'.
RealBox(int s, float a);
/*
* --------- Big 3 Member Functions -----------
*/
// Purpose: Destructor
// Postconditions: m_reals[] deallocated
~RealBox();
// Purpose: Operator=, performs a deep copy of 'rhs' into 'this' RealBox
// Parameters: rhs, RealBox to be copied
// Returns: *this
// Postconditions: *this == rhs
const RealBox& operator=(const RealBox& rhs);
// Purpose: Copy Constructor
// Parameters: rhs - RealBox to be copied
// Postconditions: *this == rhs
RealBox(const RealBox& rhs);
/*
* ----- Simple Accessor Operations -----
*/
// Purpose: Sets a value in the RealBox
// Parameters: 'i' location to set
// 'x' value to store
// PreConditions: 'i' is between the boundaries of the RealBox
// Postconditions: element 'i' in the RealBox is set to 'x'
void set( int i, float x);
/*
* ----- Complex Accessor Operations -----
*/
// Purpose: prints the RealBox
friend std::ostream& operator<< (std::ostream& out,
const RealBox& box);
}; // RealBox
#include "realbox.h"
#include <iostream>
using namespace std;
RealBox::RealBox(int s, float a)
{
m_reals = new float[s];
for (int i=0; i < s; i++)
{
m_reals[i] = a;
}
}
RealBox::~RealBox()
{
delete [] m_reals;
m_reals = NULL;
}
const RealBox& RealBox::operator =(const RealBox& rhs)
{
if(this != &rhs)
*this = rhs;
return(*this);
}
RealBox::RealBox(const RealBox& rhs)
{
m_reals = new float[m_boxsize];
*this = rhs.m_reals;
}
void RealBox::set(int i, float x)
{
m_reals[i] = x;
}
std::ostream& operator<< (std::ostream& out, const RealBox& box)
{
out <<"[ ";
for (int i = 0; i < box.m_boxsize; i++)
{
out << box.m_reals[i] << ", ";
}
out <<"]"<< endl;
return(out);
}
When I try to compile, I am getting the error:
realbox.cpp: In copy constructor ‘RealBox::RealBox(const RealBox&)’:
realbox.cpp:33:8: error: no match for ‘operator=’ (operand types are ‘RealBox’ and ‘float* const’)
*this = rhs.m_reals;
^
realbox.cpp:33:8: note: candidate is:
realbox.cpp:23:16: note: const RealBox& RealBox::operator=(const RealBox&)
const RealBox& RealBox::operator =(const RealBox& rhs)
^
realbox.cpp:23:16: note: no known conversion for argument 1 from ‘float* const’ to ‘const RealBox&’
I think my operator = overload is faulty as well but I'm not sure exactly what went wrong. It didn't give me that error until I started trying to fix. It's trying to say I'm comparing two different data types but I'm not sure how that is happening.
This line:
*this = rhs.m_reals;
Attempts to assign a float* to a RealBox object. The two types are incompatible.
Second, you failed to initialize m_boxsize when you constructed the object.
What you want to do is this:
RealBox::RealBox(const RealBox& rhs)
{
m_boxsize = rhs.boxsize;
m_reals = new float[m_boxsize];
for (int i = 0; i < m_boxsize; ++i )
m_reals[i] = rhs.m_reals[i];
}
This can be shortened to this:
RealBox::RealBox(const RealBox& rhs) : m_boxsize(rhs.m_boxsize),
m_reals(new float[rhs.m_boxsize])
{
std::copy(rhs.m_boxsize, rhs.m_boxsize + m_boxsize, m_reals);
}
In addition, your other constructor needs to initialize the m_boxsize variable:
RealBox::RealBox(int s, float a) : m_boxsize(s)
{
m_reals = new float[s];
for (int i=0; i < s; i++)
m_reals[i] = a;
}
This can also be shortened to this:
RealBox::RealBox(int s, float a) : m_boxsize(s), m_reals(new float[s])
{
std::fill( m_reals, m_reals + s, a);
}
The std::fill and std::copy are defined in the <algorithm> header.
Once you fix this, the assignment operator is very simple:
#include <algorithm>
//...
RealBox& RealBox::operator =(RealBox rhs)
{
std::swap(rhs.m_reals, m_reals);
std::swap(rhs.m_boxsize, m_boxsize);
return *this;
}
Usage of the copy/swap idiom makes this all possible. Simple as simple can be.
What is the copy-and-swap idiom?
sorry for short answer ...
first add a member to save the table size inside the costructor
RealBox::RealBox(int s, float a)
{
m_reals = new float[s];
for (int i=0; i < s; i++)
{
m_reals[i] = a;
}
m_realCount = s;
}
then replace :
RealBox::RealBox(const RealBox& rhs)
{
m_reals = new float[m_boxsize];
*this = rhs.m_reals; // << this is a big mistake
}
by :
RealBox::RealBox(const RealBox& rhs)
{
this->m_reals = new float[rhs.m_realCount];
memcpy(this->m_reals,rhs.m_reals,rhs.m_realCount*sizeof(float));
this->m_realCount = rhs.m_realCount;
}
You may need to include stdlib.h
I want to overload equal to "=" operator in C++ for
class Array
{
int *p;
int len;
};
All functions/constructor etc. are defined.
My question:
Could someone give me the prototype of the operator overloaded function?
And suppose:
Array a,b;
b=a;
Which of "a" and "b" would be passed implicitly and which explicitly?
Thanks in advance.
The prototype is Array& operator=(const Array& that).
While implementing this, remember about the rule of three and make good use of the copy-and-swap idiom.
You're looking for the assignment operator = (not equal-to, which is operator== and usually serves as an equality comparison)
class Array
{
int *p;
int len;
public:
// Assignment operator, remember that there's an implicit 'this' parameter
Array& operator=(const Array& array)
{
// Do whatever you want
std::cout << "assignment called";
return *this;
}
};
int main(void) {
Array a, b;
a = b;
}
remember that since you wrote "All functions/constructor etc. are defined" you should pay attention to what you need your class to do and possibly also implement destructor as in the rule of three (and/or take a look at its variants in C++11, might be relevant since there's no other code posted).
There is probably more than one way to do it, but here is an option.
Public Functions:
Array::Array(const Array& array)
{
Allocate(0);
*this = array;
}
Array::~Array()
{
Deallocate();
}
const Array& Array::operator=(const Array& array)
{
if (this == &array)
return *this;
Deallocate();
Allocate(array.len);
for (int i=0; i<len; i++)
p[i] = array.p[i];
return *this;
}
Non-Public Functions:
void Array::Allocate(int size)
{
len = size;
if (len > 0)
p = new int[len];
}
void Array::Deallocate()
{
if (len > 0)
delete[] p;
len = 0;
}
Of course, you can always use a vector<int> instead...
i try to use the std::map with
class DEMO {
public:
DEMO();
virtual ~DEMO();
DEMO &operator =(const DEMO &d);
DEMO(const DEMO& d);
BYTE* Arr() const;
private:
BYTE *m_array;
};
DEMO &DEMO::operator =(const DEMO &d) {
memcpy(m_array, d.Arr(), 1);
return *this;
}
DEMO::DEMO(const DEMO& d) {
//call operator=
*this = d;
}
const BYTE* DEMO::Arr() const {
return m_array;
}
DEMO::DEMO() {
m_array = new BYTE[1];
}
DEMO::~DEMO() {
if (m_array != 0)
delete [] m_array;
}
class MyClass {
private:
typedef map<unsigned int,DEMO> t_mapType;
t_mapType m_map;
void Test();
}
void MyClass::Test() {
DEMO myDEMO;
m_map[1] = myDEMO;
}
if i call Test() within the class, i get the error assert _CrtIsValidHeapPointer...
i checked with breakpoints and i see, during assingment (m_map[1] = myDEMO;) the destructor of DEMO gets called and i get the error on delete [] m_array; - how i make this running ?
The copy constructor and assignment operators are wrong. You need to allocate memory for m_array before doing memcpy. When you try to insert a DEMO object into the map using m_map[1] = myDEMO; a copy of the myDEMO is being created. To create a copy the DEMO class's copy ctor is used. Since the memory for m_array is not allocated while doing this copy, the memcpy call is crashing.
It's almost always wrong to base the copy ctor implementation on the assignment operator's. An assignment operator has to tear down the object's old state and build a new state. The copy ctor only has to build a new state.
If you want to do it this way, your copy ctor first needs to build a default state for the assignment operator to tear down. Of course, that's wasting resources.
That said, actually you should use the copy-and-swap idiom to base your assignment operator on your dtor and copy ctor instead. See here for a more thorough explanation of the above.
Use a std::vector to manage your BYTE*.
class DEMO {
public:
DEMO();
virtual ~DEMO();
//DEMO &operator =(const DEMO &d);
//DEMO(const DEMO& d);
const std::vector<BYTE>& Arr() const;
private:
std::vector<BYTE> m_array;
};
// Doesn't even need to be implemented by us anymore
//DEMO &DEMO::operator =(const DEMO &d) {
// memcpy(m_array, d.Arr(), 1);
// return *this;
//}
// Again, doesn't need to be implemented
//DEMO::DEMO(const DEMO& d) {
// //call operator=
// *this = d;
//}
// Just changed to return const vector&.
const std::vector<BYTE>& DEMO::Arr() const {
return m_array;
}
// Changed to use initializer list
DEMO::DEMO()
: m_array(1) {
// Old code: m_array = new BYTE[1];
}
// Doesn't need any code by us
DEMO::~DEMO() {
//if (m_array != 0)
// delete [] m_array;
}
i changed my code to use pointer to object instead of object for the value part in the map:
typedef map<unsigned int,DEMO*> t_mapType;
so i can assing as follow:
m_map[1] = new DEMO();
and i have to use a own free-mem method:
void DEMO::Clear() {
if (m_map.size() > 0) {
for (t_mapType::const_iterator it = m_map.begin(); it != m_mp.end(); ++it) {
if (it->second != 0)
delete it->second;
}
m_map.clear();
}
}