-
Book Overview & Buying
-
Table Of Contents
Advanced C++ [Instructor Edition]
By :
In this activity, we will develop our previous Matrix3d and Point3d classes to use a unique_ptr<> to manage the memory associated with the data structures that are required to implement these graphics classes. Let's get started:
// ... lines omitted
#include <initializer_list>
#include <ostream>
namespace acpp::gfx { // Add this line
class Point3d
{
// ... lines omitted
};
} // Add this line
Note that the closing brace that's added to the end of the file does NOT have a closing semi-colon. The nested namespace syntax acpp::gfx, is a new feature of C++17. Previously, it would have required the explicit use of the namespace keyword twice. Also, beware that, in trying to be helpful, your friendly neighborhood IDE may insert the closing brace just after the line that you put the namespace declaration.
using namespace acpp::gfx;
std::unique_ptr<float[]> m_data;
float operator()(const int row, const int column) const
{
return m_data[row][column];
}
float& operator()(const int row, const int column)
{
return m_data[row][column];
}
The problem here is that unique_ptr holds a pointer to a single dimension array and not a two- dimensional array. So, we need to convert the row and column into a single index.
float operator()(const int row, const int column) const
{
return m_data[get_index(row,column)];
}
float& operator()(const int row, const int column)
{
return m_data[get_index(row,column)];
}
private:
size_t get_index(const int row, const int column) const
{
return row * NumberColumns + column;
}
inline Matrix3d operator*(const Matrix3d& lhs, const Matrix3d& rhs)
{
Matrix3d temp(lhs); // <=== compiler error – ill formed copy constructor
temp *= rhs;
return temp;
}
Matrix3d(const Matrix3d& rhs);
Matrix3d& operator=(const Matrix3d& rhs);
Attempting to build the tests will now show that we have resolved all the issues in the header file, and that we can move onto the implementation file.
Matrix3d::Matrix3d() : m_data{new float[NumberRows*NumberColumns]}
{
for (int i{0} ; i< NumberRows ; i++)
for (int j{0} ; j< NumberColumns ; j++)
m_data[i][j] = (i==j);
}
Matrix3d::Matrix3d(std::initializer_list<std::initializer_list<float>> list)
: m_data{new float[NumberRows*NumberColumns]}
{
int i{0};
for(auto it1 = list.begin(); i<NumberRows ; ++it1, ++i)
{
int j{0};
for(auto it2 = it1->begin(); j<NumberColumns ; ++it2, ++j)
m_data[i][j] = *it2;
}
}
Matrix3d::Matrix3d() : m_data{new float[NumberRows*NumberColumns]}
{
for (int i{0} ; i< NumberRows ; i++)
for (int j{0} ; j< NumberColumns ; j++)
m_data[get_index(i, j)] = (i==j); // <= change here
}
Matrix3d::Matrix3d(std::initializer_list<std::initializer_list<float>> list)
: m_data{new float[NumberRows*NumberColumns]}
{
int i{0};
for(auto it1 = list.begin(); i<NumberRows ; ++it1, ++i)
{
int j{0};
for(auto it2 = it1->begin(); j<NumberColumns ; ++it2, ++j)
m_data[get_index(i, j)] = *it2; // <= change here
}
}
Matrix3d& Matrix3d::operator*=(const Matrix3d& rhs)
{
Matrix3d temp;
for(int i=0 ; i<NumberRows ; i++)
for(int j=0 ; j<NumberColumns ; j++)
{
temp.m_data[get_index(i, j)] = 0; // <= change here
for (int k=0 ; k<NumberRows ; k++)
temp.m_data[get_index(i, j)] += m_data[get_index(i, k)]
* rhs.m_data[get_index(k, j)];
// <= change here
}
*this = temp;
return *this;
}
Matrix3d::Matrix3d(const Matrix3d& rhs) :
m_data{new float[NumberRows*NumberColumns]}
{
*this = rhs;
}
Matrix3d& Matrix3d::operator=(const Matrix3d& rhs)
{
for(int i=0 ; i< NumberRows*NumberColumns ; i++)
m_data[i] = rhs.m_data[i];
return *this;
}
return std::move(matrix);
Matrix3d(Matrix3d&& rhs);
Matrix3d::Matrix3d(Matrix3d&& rhs)
{
//std::cerr << "Matrix3d::Matrix3d(Matrix3d&& rhs)\n";
std::swap(m_data, rhs.m_data);
}
Just a quick note about the move constructor – we did not explicitly initialize m_data like we did for the other constructors. This means that it will be initialized as empty and then swapped with the parameter that is passed in, which is a temporary and so it is acceptable for it to not hold an array after the transaction – it removes one allocation and deallocation of memory.
std::unique_ptr<float[]> m_data;
inline std::ostream&
operator<<(std::ostream& os, const Point3d& pt)
{
const char* sep = "[ ";
for(int i{0} ; i < Point3d::NumberRows ; i++)
{
os << sep << pt.m_data[i];
sep = ", ";
}
os << " ]";
return os;
}
Point3d::Point3d() : m_data{new float[NumberRows]}
{
for(int i{0} ; i < NumberRows-1 ; i++) {
m_data[i] = 0;
}
m_data[NumberRows-1] = 1;
}
Point3d::Point3d(std::initializer_list<float> list)
: m_data{new float[NumberRows]}
Change the font size
Change margin width
Change background colour