compiling issue with constructor in c++ - c++

I'm having a bad time with this issue because I cannot resolve it. I've designed a matrix template class and a pixel class and now I'd like to join them but I'm not been able to accomplish the task.
The error I'm having is the following:
pgm_matrix.cpp: In constructor ‘PGMmatrix::PGMmatrix(unsigned int, unsigned int)’:
pgm_matrix.cpp:13:23: error: expression list treated as compound expression in initializer [-fpermissive]
Matrix<Pixel>* m(l, h);
^
pgm_matrix.cpp:13:23: error: invalid conversion from ‘unsigned int’ to ‘Matrix<Pixel>*’ [-fpermissive]
My Pixel.hpp:
#ifndef __PIXEL_HPP__
#define __PIXEL_HPP__
class Pixel
{
private:
int posx_;
int posy_;
unsigned int intensity_;
public:
Pixel();
Pixel(int, int, unsigned int);
Pixel(Pixel const &);
~Pixel();
bool operator==(const Pixel &)const;
bool operator!=(const Pixel &)const;
Pixel const &operator=(Pixel const &);
void operator()(int, int, unsigned int);
int get_pixel_pos_x() const;
int get_pixel_pos_y() const;
unsigned int get_pixel_intensity() const;
};
#endif
My matrix.hpp:
#ifndef __MATRIX_HPP__
#define __MATRIX_HPP__
template<typename T>
class Matrix
{
private:
T** matrix_;
unsigned int rows_;
unsigned int cols_;
public:
Matrix();
Matrix(unsigned int, unsigned int);
Matrix(Matrix const &);
~Matrix();
bool operator==(const Matrix &)const;
bool operator!=(const Matrix &)const;
Matrix const &operator=(Matrix const &);
T &operator()(unsigned int, unsigned int);
T const &operator()(unsigned int, unsigned int) const;
T& data(unsigned int, unsigned int);
T const &data(unsigned int, unsigned int) const;
unsigned int const get_rows()const;
unsigned int const get_cols()const;
};
template<typename T>
Matrix<T>::Matrix() : matrix_(0), rows_(0), cols_(0)
{
}
template<typename T>
Matrix<T>::Matrix(unsigned int rows, unsigned int cols)
{
matrix_ = new T*[rows];
for(unsigned int i=0; i < rows; i++)
matrix_[i] = new T[cols];
rows_ = rows;
cols_ = cols;
}
template<typename T>
Matrix<T>::Matrix(Matrix<T> const & m_orig)
{
rows_ = m_orig.rows_;
cols_ = m_orig.cols_;
matrix_ = new T*[rows_];
for(unsigned int i=0; i < rows_; i++)
{
matrix_[i] = new T[cols_];
for(unsigned int j=0; j < cols_; j++)
matrix_[i][j]=m_orig.matrix_[i][j];
}
}
template<typename T>
Matrix<T>::~Matrix()
{
for(unsigned int i=0; i < rows_; i++)
delete matrix_[i];
delete matrix_;
rows_ = 0;
cols_ = 0;
}
template<typename T>
bool Matrix<T>::operator==(const Matrix & m)const
{
if(m.cols_ != cols_ || m.rows_ != rows_)
return false;
for(unsigned int i=0; i < rows_; i++)
{
for(unsigned int j=0; j < cols_; j++)
{
if(m.matrix_[i][j] != matrix_[i][j])
return false;
}
}
return true;
}
template<typename T>
bool Matrix<T>::operator!=(const Matrix & m)const
{
if( m == *this)
return false;
return true;
}
template<typename T>
Matrix<T> const &Matrix<T>::operator=(Matrix const & m_orig)
{
if(this != &m_orig)
{
for(unsigned int k=0; k < rows_; k++)
delete matrix_[k];
delete matrix_;
rows_ = m_orig.rows_;
cols_ = m_orig.cols_;
matrix_ = new T*[rows_];
for(unsigned int i=0; i < rows_; i++)
{
matrix_[i] = new T[cols_];
for(unsigned int j=0; j < cols_; j++)
matrix_[i][j]=m_orig.matrix_[i][j];
}
}
return *this;
}
template<typename T>
T &Matrix<T>::operator()(unsigned int i, unsigned int j)
{
return matrix_[i][j];
}
template<typename T>
T const &Matrix<T>::operator()(unsigned int i, unsigned int j) const
{
return matrix_[i][j];
}
template<typename T>
T& Matrix<T>::data(unsigned int i, unsigned int j)
{
return matrix_[i][j];
}
template<typename T>
T const &Matrix<T>::data(unsigned int i, unsigned int j) const
{
return matrix_[i][j];
}
template<typename T>
unsigned int const Matrix<T>::get_rows() const
{
return rows_;
}
template<typename T>
unsigned int const Matrix<T>::get_cols() const
{
return cols_;
}
#endif
Finally the code that fails:
#include "pgm_matrix.hpp"
#include "matrix.hpp"
#include "pixel.hpp"
PGMmatrix::PGMmatrix(unsigned int l, unsigned int h)
{
large_ = l;
height_ = h;
Matrix<Pixel>* m(l, h);
matrix_ = m;//here is the problem
}
int main()
{
PGMmatrix p(2,2);
return 0;
}
PGM_matrix.hpp:
#ifndef __PGM_MATRIX_HPP__
#define __PGM_MATRIX_HPP__
#include "matrix.hpp"
#include "pixel.hpp"
class PGMmatrix
{
private:
Matrix<Pixel>* matrix_;
unsigned int large_;
unsigned int height_;
public:
PGMmatrix();
PGMmatrix(unsigned int, unsigned int);
PGMmatrix(PGMmatrix const &);
~PGMmatrix();
bool operator==(const PGMmatrix &) const;
bool operator!=(const PGMmatrix &) const;
PGMmatrix const &operator=(PGMmatrix const &);
void operator()(int, int, Pixel);
};
#endif
to compile I do:
g++ pixel.o pgm_matrix.cpp -o pgm
How can I solve my problem?

Try using 'new' to create a new instance on the heap.
...
PGMmatrix::PGMmatrix(unsigned int l, unsigned int h)
{
large_ = l;
height_ = h;
matrix_ = new Matrix<Pixel>(l, h); // Use new, to create a new instance on the heap
}
...
Or better do not use a pointer.
...
class PGMmatrix
{
private:
Matrix<Pixel> matrix_;
...

Related

move constructor error and delegating using a move constructor [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 4 years ago.
Improve this question
why does this implementation for the move assignment operator give the error in the attached image
Spreadsheet::Spreadsheet(Spreadsheet&& src) noexcept :Spreadsheet(src.width, src.height) {
this->cells = src.cells; // Shallow copy of data
src.cells = nullptr; src.width = 0; src.height = 0; // Reset the source object, because ownership has been moved!
};
Spreadsheet& Spreadsheet::operator=(Spreadsheet&& rhs) noexcept {
if (this == &rhs) return *this;
for (size_t i = 0; i < width; i++) delete[] cells[i];
delete[] cells;
this->width = rhs.width; this->height = rhs.height;
this->cells = rhs.cells;
rhs.cells = nullptr; rhs.width = 0; rhs.height = 0;
return *this;
};
I attached the full resources.
the Spreadsheet class definition
SPreadsheet.h
#pragma once
#include "SpreadsheetCell.h"
class Spreadsheet
{
public:
Spreadsheet(size_t, size_t);
~Spreadsheet();//1
void setCellAt(size_t, size_t, const SpreadsheetCell&);
void verifyCoordinate(size_t, size_t) const;
void swap(Spreadsheet);
SpreadsheetCell& getCellAt(size_t, size_t);
Spreadsheet(const Spreadsheet&); //copy constructor 2
Spreadsheet& operator=(const Spreadsheet& rhs); //assignment operator 3
Spreadsheet(Spreadsheet&& src) noexcept; // Move constructor 4
Spreadsheet& operator=(Spreadsheet&& rhs) noexcept; // Move assign 5
private:
size_t width = 0;
size_t height = 0;
SpreadsheetCell** cells = nullptr;
};
the Spreadsheet class implementation
Spreadsheet.cpp
#include "stdafx.h"
#include "Spreadsheet.h"
#include<utility>
Spreadsheet::Spreadsheet(size_t width, size_t height) :width(width), height(height)
{
cells = new SpreadsheetCell*[width];
for (size_t i = 0; i < height; i++) cells[i] = new SpreadsheetCell[height];
}
void Spreadsheet::verifyCoordinate(size_t x, size_t y) const
{
(x >= width || y >= height) ? throw std::out_of_range("") : void();// void();
}
void Spreadsheet::setCellAt(size_t x, size_t y, const SpreadsheetCell& cell)
{
verifyCoordinate(x, y);
cells[x][y] = cell;
}
SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y) {
verifyCoordinate(x, y);
return cells[x][y];
}
Spreadsheet::~Spreadsheet()
{
for (size_t i = 0; i < width; i++) {
delete[] cells[i];
};
delete[] cells;
cells = nullptr;
}
Spreadsheet::Spreadsheet(const Spreadsheet& src) :Spreadsheet(src.width, src.height) {
for (size_t i = 0; i < width; i++)
for (size_t j = 0; j < height; j++) cells[i][j] = src.cells[i][j];
}
void Spreadsheet::swap(Spreadsheet copyOfRhsDueToBassByVal) {
std::swap(copyOfRhsDueToBassByVal.width, this->width);
std::swap(copyOfRhsDueToBassByVal.height, this->height);
std::swap(copyOfRhsDueToBassByVal.cells, this->cells);
}
Spreadsheet& Spreadsheet::operator=(const Spreadsheet &rhs) {
if (this == &rhs) return *this;//we cant use return rhs because it is const but the function header returnning a non-const;
swap(rhs); return *this;
}
Spreadsheet::Spreadsheet(Spreadsheet&& src) noexcept :Spreadsheet(src.width, src.height) {
this->cells = src.cells; // Shallow copy of data
src.cells = nullptr; src.width = 0; src.height = 0; // Reset the source object, because ownership has been moved!
};
Spreadsheet& Spreadsheet::operator=(Spreadsheet&& rhs) noexcept {
if (this == &rhs) return *this;
for (size_t i = 0; i < width; i++) delete[] cells[i];
delete[] cells;
this->width = rhs.width; this->height = rhs.height;
this->cells = rhs.cells;
rhs.cells = nullptr; rhs.width = 0; rhs.height = 0;
return *this;
};
the SpreadsheetCell class definition
SPreadsheetCell.h
#pragma once
#include <string>
#include <string_view>
#include<iostream>
using namespace std;
class SpreadsheetCell
{
public:
SpreadsheetCell() = default;
SpreadsheetCell(double initialValue);
SpreadsheetCell(std::string_view initialValue);
void setValue(double);
double getValue() const;
void setString(std::string_view);
string getString() const;
private:
string doubleToString(double) const;
double stringToDouble(std::string_view) const;
double value = 0;
};
the SpreadsheetCell class implementation
Spreadsheetcell.cpp
#include "stdafx.h"
#include "SpreadSheetCell.h"
SpreadsheetCell::SpreadsheetCell(double value) :value(value) {};
SpreadsheetCell::SpreadsheetCell(std::string_view strv) { value = stringToDouble(strv); };
void SpreadsheetCell::setValue(double value) { this->value = value; };
double SpreadsheetCell::getValue() const { return value; };
void SpreadsheetCell::setString(std::string_view str) { value = stringToDouble(str); };
string SpreadsheetCell::getString() const { return doubleToString(value); };
string SpreadsheetCell::doubleToString(double inValue) const {
return to_string(inValue);
}
double SpreadsheetCell::stringToDouble(string_view strv) const {
return strtod(strv.data(), nullptr);
}
You have several logic bugs in your code:
your allocating constructor is not looping through the 1st dimension array correctly. You are allocating an array with width number of elements, and then looping through it as if it had height number of elements instead. If width < height, you exceed the bounds of the array and corrupt memory. If width > height, you don't populate the entire array, leaving it with pointers of indeterminate values.
Your move constructor is leaking memory. It delegates to the allocating constructor instead of the default constructor, so a new array is allocated, and then it leaks that array. A move constructor should not be allocating anything at all.
your swap() is not swapping correctly. The purpose of swap() is to exchange the contents of two objects with each other, but your input parameter is being passed by value, so any object passed to it gets copied first, and then you are exchanging with the copied object, not the original object. The original object is unchanged. So you must pass the parameter by reference instead.
Also, a typical and preferable implementation for the move constructor and move assignment operator is to simply swap the contents of the moved-to and moved-from objects. Let the destructor of the moved-from object free any old resources. Don't waste time freeing the old resources before moving the new resources.
Try something more like this instead:
#pragma once
#include "SpreadsheetCell.h"
class Spreadsheet
{
public:
Spreadsheet() = default;
Spreadsheet(size_t, size_t);
Spreadsheet(const Spreadsheet &);
Spreadsheet(Spreadsheet &&) noexcept;
~Spreadsheet();
Spreadsheet& operator=(const Spreadsheet &);
Spreadsheet& operator=(Spreadsheet &&) noexcept;
SpreadsheetCell& getCellAt(size_t, size_t);
void setCellAt(size_t, size_t, const SpreadsheetCell&);
void swap(Spreadsheet &);
private:
size_t width = 0;
size_t height = 0;
SpreadsheetCell** cells = nullptr;
void verifyCoordinate(size_t, size_t) const;
};
void swap(Spreadsheet &lhs, Spreadsheet &rhs);
#include "stdafx.h"
#include "Spreadsheet.h"
#include <utility>
Spreadsheet::Spreadsheet() noexcept
: cells(nullptr), width(0), height(0)
{
}
Spreadsheet::Spreadsheet(int width, int height)
: cells(nullptr), width(width), height(height)
{
cells = new SpreadsheetCell*[width];
for (size_t i = 0; i < width; ++i)
cells[i] = new SpreadsheetCell[height];
}
Spreadsheet::Spreadsheet(const Spreadsheet &src)
: Spreadsheet(src.width, src.height)
{
for (size_t i = 0; i < width; ++i)
for (size_t j = 0; j < height; ++j)
cells[i][j] = src.cells[i][j];
}
Spreadsheet::Spreadsheet(Spreadsheet &&src) noexcept
: Spreadsheet()
{
src.swap(*this);
}
Spreadsheet::~Spreadsheet()
{
for (size_t i = 0; i < width; ++i)
delete[] cells[i];
delete[] cells;
}
Spreadsheet& Spreadsheet::operator=(const Spreadsheet &rhs)
{
if (this != &rhs)
Spreadsheet(rhs).swap(*this);
return *this;
}
Spreadsheet& Spreadsheet::operator=(Spreadsheet &&rhs) noexcept
{
rhs.swap(*this);
return *this;
}
SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y)
{
verifyCoordinate(x, y);
return cells[x][y];
}
void Spreadsheet::setCellAt(size_t x, size_t y, const SpreadsheetCell& cell)
{
verifyCoordinate(x, y);
cells[x][y] = cell;
}
void Spreadsheet::swap(Spreadsheet &other)
{
std::swap(cells, other.cells);
std::swap(width, other.width);
std::swap(height, other.height);
}
void Spreadsheet::verifyCoordinate(size_t x, size_t y) const
{
if (x >= width || y >= height)
throw std::out_of_range("");
}
void swap(Spreadsheet &lhs, Spreadsheet &rhs)
{
lhs.swap(rhs);
}
That being said, this code can be greatly simplified if you use std::vector instead of raw arrays:
#pragma once
#include "SpreadsheetCell.h"
#include <vector>
class Spreadsheet
{
public:
Spreadsheet() = default;
Spreadsheet(size_t, size_t);
Spreadsheet(const Spreadsheet &) = default;
Spreadsheet(Spreadsheet &&) noexcept = default;
Spreadsheet& operator=(const Spreadsheet &) = default;
Spreadsheet& operator=(Spreadsheet &&) noexcept = default;
SpreadsheetCell& getCellAt(size_t, size_t);
void setCellAt(size_t, size_t, const SpreadsheetCell&);
void swap(Spreadsheet &);
private:
std::vector<std::vector<SpreadsheetCell>> cells;
};
void swap(Spreadsheet &lhs, Spreadsheet &rhs);
#include "stdafx.h"
#include "Spreadsheet.h"
#include <utility>
Spreadsheet::Spreadsheet(int width, int height)
{
cells.resize(width);
for (size_t i = 0; i < width; ++i)
cells[i].resize(height);
}
SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y)
{
return cells.at(x).at(y);
}
void Spreadsheet::setCellAt(size_t x, size_t y, const SpreadsheetCell& cell)
{
cells.at(x).at(y) = cell;
}
void Spreadsheet::swap(Spreadsheet &other)
{
std::swap(cells, other.cells);
}
void swap(Spreadsheet &lhs, Spreadsheet &rhs)
{
lhs.swap(rhs);
}

exc_bad_access code 1 error

After a bit of bug searching, I've found that my code leaves with exit code 11 at a certain point, and this is because an EXC_BAD_ACCESS error with code 1. After some googling, I see this must be due to some memory mismanagement, but I'm new to C++ and nothing seems obvious to me.
The code is exiting at the line
fieldFuncts[field](string, equal, validOps, length, difficulty, rng, opGen);
in the file (last function)
//
// Created by Anthony Monterrosa on 4/17/18.
//
#include "MathExpr.h"
#include <list>
#include <iostream>
#include <random>
std::vector<std::function<void(std::vector<MathExpr::CharType> &, MathExpr::NumType &, std::vector<MathExpr::NumType> &)>> MathExpr::layerFuncts;
std::vector<std::function<void(std::vector<MathExpr::CharType> &, MathExpr::NumType &, std::vector<MathExpr::Op> &, unsigned char, unsigned char, std::mt19937 &, std::uniform_int_distribution<MathExpr::OpType> &)>> MathExpr::fieldFuncts;
void MathExpr::init() {
initLayerFuncts();
initFieldFuncts();
}
void MathExpr::initLayerFuncts() {
layerFuncts.resize(Op::EOOE);
layerFuncts[static_cast<unsigned long>(Op::addition)] = [](std::vector<MathExpr::CharType> &string, NumType &equal, std::vector<NumType> & otherArgs) -> void {
string.insert(string.end(), {' ', opToChar(Op::addition), ' '});
equal += otherArgs[0];
std::vector<MathExpr::CharType> digits = intToDigit(otherArgs[0]);
for(int i = 0; i < digits.size(); i++ ) {
string.push_back(digits[i]);
}
};
layerFuncts[static_cast<unsigned long>(Op::subtraction)] = [](std::vector<MathExpr::CharType> &string, MathExpr::NumType &equal, std::vector<NumType> & otherArgs) -> void {
string.insert(string.end(), {' ', opToChar(Op::subtraction), ' '});
equal -= otherArgs[0];
std::vector<MathExpr::CharType> digits = intToDigit(otherArgs[0]);
for(int i = 0; i < digits.size(); i++ ) {
string.push_back(digits[i]);
}
};
}
void MathExpr::initFieldFuncts() {
fieldFuncts.resize(Field::EOFE);
fieldFuncts[static_cast<unsigned long>(Field::integers)] = [](std::vector<MathExpr::CharType> &string, NumType &equal, std::vector<MathExpr::Op> &validOps, unsigned char length, unsigned char difficulty, std::mt19937 &rng, std::uniform_int_distribution<MathExpr::OpType> &opGen) -> void {
std::uniform_int_distribution<MathExpr::NumType> numGen(1, static_cast<MathExpr::NumType>(pow(10, difficulty)));
equal = numGen(rng);
std::vector<MathExpr::CharType> digits = intToDigit(equal);
for(int i = 0; i < digits.size(); i++ ) {
string.push_back(digits[i]);
}
for (int i = 0; i < length - 1; i++) {
MathExpr::Op op = validOps[opGen(rng)];
int count = otherArgsCount(op);
std::vector<MathExpr::NumType> otherArgs(count);
for(int j = 0; j < count; j++) {
otherArgs[j] = (numGen(rng));
}
layer(string, equal, op, otherArgs);
}
};
}
char MathExpr::opToChar(OpType ordinal) {
return opToChar(static_cast<Op>(ordinal));
}
char MathExpr::opToChar(Op op) {
switch(op) {
case Op::addition : return '+';
case Op::subtraction : return '-';
default : return '_';
}
}
MathExpr::NumType MathExpr::otherArgsCount(MathExpr::Op op) {
switch(op) {
case Op::addition : return 1;
case Op::subtraction : return 1;
default : return 0;
}
}
std::vector<MathExpr::CharType> MathExpr::intToDigit(MathExpr::NumType num) {
std::vector<MathExpr::CharType> digits;
while(num >= 10) {
digits.insert(digits.begin(),'0' + static_cast<MathExpr::CharType>(num % 10));
num /= 10;
} digits.insert(digits.begin(), '0' + static_cast<MathExpr::CharType>(num));
return digits;
}
bool MathExpr::initBool = false;
MathExpr::MathExpr(std::vector<CharType> exp, MathExpr::NumType equal) {
if(!initBool) init();
this->string = std::vector<CharType>(exp);
this->equal = equal;
}
void MathExpr::print(MathExpr &exp) {
for(int i = 0; i < exp.string.size(); i++) {
std::cout << exp.string[i];
}
}
void MathExpr::layer(std::vector<MathExpr::CharType> &string, MathExpr::NumType &equal, MathExpr::Op op, std::vector<MathExpr::NumType> &otherArgs) {
layerFuncts[op](string, equal, otherArgs);
}
MathExpr MathExpr::generate(std::vector<MathExpr::Op> &validOps, MathExpr::Field field, unsigned char length, unsigned char difficulty) {
std::vector<MathExpr::CharType> string;
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<MathExpr::OpType> opGen(0, static_cast<MathExpr::OpType>(validOps.size() - 1));
MathExpr::NumType equal;
fieldFuncts[field](string, equal, validOps, length, difficulty, rng, opGen);
return MathExpr::MathExpr(string, equal);
}
here is the corresponding .h file
//
// Created by Anthony Monterrosa on 4/17/18.
//
// EO_E -> "end of _ enum".
#ifndef MATHTESTGENERATOR_MATHEXPR_H
#define MATHTESTGENERATOR_MATHEXPR_H
#include <functional>
#include <random>
#include <vector>
class MathExpr {
public:
using FieldType = unsigned char;
using OpType = unsigned char;
using NumType = short int;
using CharType = char;
enum Field : FieldType {
integers,
EOFE // rational, real, complex.
};
enum Op : OpType {
addition,
subtraction,
EOOE // multiplication, division, absolute value, radical
};
explicit MathExpr(std::vector<CharType>, NumType);
std::vector<CharType> string;
NumType equal;
static void print(MathExpr &);
static MathExpr generate(std::vector<Op> &, Field = Field::integers, unsigned char length = 2, unsigned char difficulty = 1);
//protected:
static void init();
static bool initBool;
static void layer(std::vector<MathExpr::CharType> &, NumType &, Op, std::vector<NumType> &);
static NumType otherArgsCount(Op);
static std::vector<CharType> intToDigit(NumType);
static char opToChar(OpType);
static char opToChar(Op);
static std::vector<std::function<void(std::vector<MathExpr::CharType> &, NumType &, std::vector<NumType> &)>> layerFuncts;
static void initLayerFuncts();
static std::vector<std::function<void(std::vector<MathExpr::CharType> &, NumType &, std::vector<MathExpr::Op> &, unsigned char, unsigned char, std::mt19937 &, std::uniform_int_distribution<MathExpr::OpType> &)>> fieldFuncts;
static void initFieldFuncts();
};
#endif //MATHTESTGENERATOR_MATHEXPR_H
My gut says the error has to do with the "string" vector, but I'm unsure of how to tell. I would appreciate insight into the problem.

Fast allocation of vectors of vectors

I store 3D data in a std::vector-based structure:
std::shared_ptr< std::vector< std::vector< std::vector< Type > > > > data;
I allocate this structure by calling resize while iterating through the vectors:
arraydata.reset(new std::vector< std::vector< std::vector< Type > > >());
arraydata->resize(m_width);
for (unsigned int col_index = 0; col_index < m_width; ++col_index)
{
(*arraydata)[col_index].resize(m_height);
for (unsigned int line_index = 0; line_index < m_height; ++line_index)
{
(*arraydata)[col_index][line_index].resize(m_nbbands);
}
}
But this allocation takes a lot of time when the dimensions are big...
Is there a way to allocate in a single operation all the needed space (with malloc(m_width*m_height*m_nbbands*sizeof(Type)) for example) and then to assign to each vector its own data space in the global space ? Would it be more performant ?
Edit: I tested #justin-time's idea
arraydata.reset(new std::vector< std::vector< std::vector< T > > >(m_width,
std::vector< std::vector< T > >(m_height, std::vector< T > (m_nbbands))));
gives an execution time comparable to original code, around 4.9 s for allocation and 40 s for deallocation ???
This can be seen in the memory manager:
I don't succeed in testing allocation from a malloc, this code fails at std::vector< T > tmp(datptr, (T*)(datptr+arraySize));
unsigned int arraySize = m_nbbands*sizeof(T);
T *datptr = (T*)malloc(m_width*m_height*arraySize);
arraydata.reset(new std::vector< std::vector< std::vector< T > > >(m_width));
for (unsigned int col_index = 0; col_index < m_width; ++col_index)
{
(*arraydata)[col_index].resize(m_height);
for (unsigned int line_index = 0; line_index < m_height; ++line_index)
{
std::vector< T > tmp(datptr, (T*)(datptr+arraySize));
(*arraydata)[col_index][line_index].swap(tmp);
// also tested with same results:
//(*arraydata)[col_index][line_index] =
// std::vector< T >(datptr, (T*)(datptr+arraySize));
datptr += arraySize;
}
}
Don't use a vector of vector of vectors. Use a class which has an internal array and then provides a way to access the elements. For example:
template <typename T>
class vec3d {
std::vector<T> data;
size_t xmax, ymax, zmax;
public:
T& operator()(size_t x, size_t y, size_t z)
{ return data[x+y*xmax+z*xmax*ymax]; }
const T& operator()(size_t x, size_t y, size_t z)
{ return data[x+y*xmax+z*xmax*ymax]; }
vec3d(size_t x, size_t y, size_t z)
: xmax(x), ymax(y), zmax(z), data(x*y*z) {}
T& v(size_t x, size_t y, size_t z) { return (*this)(x,y,z); }
};
access would then be like
shared_ptr<vec3d<int>> p = make_shared<vec3d<int>>(10, 20, 30);
p->v(5,6,7) = 14;
or
vec3d vec(5,6,7);
vec(1,2,4) = 16.0f; // Fortran style indexing.
You will probably want some more members to allow iteration, the dimensions, etc. Because this is a single allocation, it will be much faster.
Following Martin Bonner's answer, I came to the following solution, for which allocation and deallocation take less than a second.
Data is accessible with arraydata[x][y][z].
arraydata = std::make_shared< CImageStorage< T > >(m_width,
m_height, m_nbbands, bppixel);
with
template<class T>
class CImageStorage1D
{
T* data;
unsigned int m_nbbands;
public:
CImageStorage1D(T* p, unsigned int nbbands) :
data(p), m_nbbands(nbbands) {}
T& DataPtr(unsigned int band) { return data[band]; }
const T& DataPtr(unsigned int band) const { return data[band]; }
T& operator[](unsigned int band) { return (data[band]); }
const T& operator[] (unsigned int band) const { return (data[band]); }
unsigned int size()const { return m_nbbands; }
};
template<class T>
class CImageStorage2D
{
T* data;
unsigned int m_height, m_nbbands, m_bppixel;
public:
CImageStorage2D(T* p, unsigned int height, unsigned int nbbands,
unsigned int bppixel, std::shared_ptr< std::vector<int> > heightShift) :
data(p), m_height(height), m_nbbands(nbbands), m_bppixel(bppixel) {}
T* DataPtr(unsigned int height) { return (T*)(data+m_height*m_nbbands); }
const T* DataPtr(unsigned int height) const {
return (T*)(data+m_height*m_nbbands); }
CImageStorage1D<T> operator[](unsigned int height) {
return CImageStorage1D<T>((T*)(data+m_height*m_nbbands), m_nbbands); }
const CImageStorage1D<T> operator[] (unsigned int height) const {
return CImageStorage1D<T>((T*)(data+m_height*m_nbbands), m_nbbands); }
unsigned int size()const { return m_height; }
};
template<class T>
class CImageStorage
{
T* data;
unsigned int m_width, m_height, m_nbbands, m_bppixel;
public:
CImageStorage(unsigned int width, unsigned int height, unsigned int nbbands,
unsigned int bppixel) :
m_width(width), m_height(height), m_nbbands(nbbands), m_bppixel(bppixel)
{
data = (T*)malloc(m_width*m_height*m_nbbands*m_bppixel);
}
~CImageStorage() { free(data); }
bool IsValid() { return (data != nullptr); }
T** DataPtr(unsigned int width) {
return (T**)(data+width*m_height*m_nbbands); }
const T** DataPtr(unsigned int width) const {
return (T**)(data+width*m_height*m_nbbands); }
CImageStorage2D<T> operator[](unsigned int width) {
return CImageStorage2D<T>( (T*)(data+width*m_height*m_nbbands),
m_height, m_nbbands, m_bppixel); }
const CImageStorage2D<T> operator[] (unsigned int width) const {
return CImageStorage2D<T>((T*)(data+width*m_height*m_nbbands),
m_height, m_nbbands, m_bppixel); }
unsigned int size()const { return m_width; }
};

C++ : A program compiled and run on CodeBlocks works but from Terminal it gives error statement

I'm having some issues with the Virtual Machine I was supposed to work with to make a C++ project, it regularly compiles both on DevC++ and CodeBlocks (Eureka!), runs and does exactly what it is meant for.
Anyway, I tried to start the execution from the Terminal but it crashes giving the following message:
main.cpp:(.text.startup+0x1586): undefined reference to `move_red(vettore<vettore<blue_car> >*, vettore<vettore<red_car> >*, unsigned int, unsigned int, unsigned int*)'
(It actually gives this error with different methods, but the error issue is the same.)
From Terminal, I executed using:
chmod +x build.sh; $ g++ -O2 -std=c++11 -o output main.cpp
This is the incriminated function:
void move_red(vettore<vettore<blue_car> > * v_col, vettore< vettore< red_car> > * v_row,unsigned int M,unsigned int N,unsigned int *n){
vettore<blue_car> * pb;
vettore<red_car> * pr;
for(unsigned int kk=0;kk<M;kk++){
pr=&((*v_row)[kk]);
for(unsigned int ll=0;ll<n[kk];ll++){
(pr->get_obj()).set_bloc(is_bloc_r(pr,&((*v_row)[kk]),v_col));
pr=pr->get_next();
}
}
for(unsigned int kk=0;kk<M;kk++){
pr=&((*v_row)[kk]);
unsigned int ll;
for(ll=0;ll<n[kk]-1;ll++){
if ((pr->get_obj().get_bloc()==0)) pr->get_obj().move_red();
pr=pr->get_next();
}
if((pr->get_obj().get_j()==N-1)&&((pr->get_obj().get_bloc()==0))){
pr->get_obj().move_red_border();
((*v_row)[kk]).order();
}
else if((pr->get_obj().get_bloc()==0)){
pr->get_obj().move_red();
}
}
};
void move_blue(vettore<vettore<blue_car> > * v_col, vettore< vettore< red_car> > * v_row,unsigned int M,unsigned int N,unsigned int *m){
vettore<blue_car> * pb;
vettore<red_car> * pr;
for(unsigned int ll=0;ll<N;ll++){
pb=&((*v_col)[ll]);
for(unsigned int kk=0;kk<m[ll];kk++){
(pb->get_obj()).set_bloc(is_bloc_b(pb,&((*v_col)[ll]),v_row));
pb=pb->get_next();
}
}
for(unsigned int ll=0;ll<N;ll++){
pb=&((*v_col)[ll]);
unsigned int kk;
for(/*unsigned int */kk=0;kk<m[ll]-1;kk++){
if ((pb->get_obj().get_bloc()==0)&&pb->get_next()!=nullptr) pb->get_obj().move_blue();
pb=pb->get_next();
}
if((pb->get_obj().get_i()==M-1)&&((pb->get_obj().get_bloc()==0))){ pb->get_obj().move_blue_border();
((*v_col)[ll]).order();
}
else if((pb->get_obj().get_bloc()==0)){
pb->get_obj().move_blue();
}
}
};
If needed, this is the main:
int main(int argc, char *argv[]){
bool error=0;
ifstream file("problem.csv");
if(file.fail()) {
error=1;
}
unsigned int N = 0;
unsigned int M = 0;
char c;
int i=-1,j=0, k=0, n_iter, j_temp =0;
vettore<blue_car> vb;
vettore<red_car> vr;
vettore< vettore <red_car> > v_row(vr);
vettore< vettore <blue_car> > v_col(vb);
vettore<unsigned int> iter(0);
std::string iterazioni;
std::string iteraz;
if(!error){
std::getline(file,iterazioni,'\n');
stringstream it(iterazioni);
while (it.good() && i==-1) {
std::getline(it,iteraz, ',');
iter[k] = atoi(iteraz.c_str());
if(iter[k]<0){
error=1;
break;
}
iter.append(0);
k++;
}
iter.remove_tail();
i=0;
n_iter=iter.get_size();
}
if(!error){
while(file.get(c) && !error)
{
if((v_row.get_size()<i+1)||(v_col.get_size()<j+1)){
if(i==0) {j_temp=v_col.get_size();}
while(v_row.get_size()<1+i){
v_row.insert_tail(vr);
}
while(v_col.get_size()<j+1){
v_col.insert_tail(vb);
}
}
if (c=='1'){
if(v_col[j].get_size()==1 && ((v_col[j])[0]).has_sense()==0){
v_col[j][0].set_2(i,j);
}
else{
blue_car * add_b = new blue_car;
add_b->set_2(i,j);
(v_col[j]).insert_tail(*add_b);
delete add_b;
}
}
if (c=='2'){
if(v_row[i].get_size()==1 && ((v_row[i])[0]).has_sense()==0){
v_row[i][0].set_2(i,j);
}
else{
red_car * add_r = new red_car;
add_r->set_2(i,j);
(v_row[i]).insert_tail(*add_r);
delete add_r;
}
}
if (c==',') j++;
if (c=='\n'){
i++;
if (j != j_temp){
error=1;
break;
}
j=0;
}
if ((c!='\n') && (c!=',') && (c!='0') && (c!='1') && (c!='2')){
error=1;
break;
}
//n_iter = k-1;
N=v_col.get_size();
M=v_row.get_size();
}
file.close();
}
//n_iter =iter.get_size();
M=v_row.get_size();
N=v_col.get_size();
unsigned int *n= new unsigned int[M];
unsigned int *m= new unsigned int[N];
for(int i=0;i<M;i++) n[i]=v_row[i].get_size();
for(int i=0;i<N;i++) m[i]=v_col[i].get_size();
unsigned int * iter_a= new unsigned int[iter.get_size()];
for(unsigned int y=0;y<n_iter;y++) iter_a[y]=iter[y];
std::sort(iter_a, iter_a + n_iter);
unsigned int temp_iniz_iter = 0;
unsigned int temp_fine_iter;// = iter_a[0];
for(int volte = 0; volte < n_iter; volte ++) {
temp_fine_iter = iter_a[volte];
for(int iter__ = temp_iniz_iter; iter__ < temp_fine_iter; iter__ ++) {/
if(temp_iniz_iter % 2){
move_red(&v_col,&v_row,M,N,n);
iter__++;
if(iter__<temp_fine_iter) move_blue(&v_col,&v_row,M,N,m);
}
else{
move_blue(&v_col,&v_row,M,N,m);
iter__++;
if(iter__<temp_fine_iter) move_red(&v_col,&v_row,M,N,n);
}
}
print_csv(temp_fine_iter, &v_row, M, &v_col, N);
temp_iniz_iter = temp_fine_iter;
}
//print_csv(temp_fine_iter, &v_row, M, &v_col, N);
delete[] iter_a;
/*if(!error) std::cout<<"Il programma Ë terminato con successo\a"<<endl;
else std::cout<<"Il programma Ë terminato con errori"<<endl;
system("PAUSE");*/
return EXIT_SUCCESS;
}
And these are my classes:
template<class T> class vettore{
private:
T my_object; //container
vettore <T> * next; //puntatore al prossimo elemento della lista
public:
vettore():next(nullptr){}; //default constructor
vettore(T oggetto, vettore <T> * successivo=nullptr):next(successivo),my_object(oggetto){}; //faccio puntare la lista a quell'elemento
vettore(const vettore <T> &x):next(x.next),my_object(x.my_object){}; //copy constructor
~vettore(){//destructor
if(next!=nullptr){
delete next;
delete this;
}
};
vettore <T> * get_next(){
return next;};
T get_my(){return my_object;};
vettore<T> * ret_punt(unsigned int n){
if(n==0) return this;
if(n>=this->get_size()){std::cout<<"FUORI"<<std::endl;
return this;}
vettore<T> * p=this;
for(unsigned int i=0;i<n;i++) p=p->get_next();
return p;
};
T& get_obj(){ //ottenere l'oggetto by reference
return my_object;
};
vettore& operator=(vettore &x){ //overloading dell'operatore =
if(this!=nullptr) delete this;
unsigned int n;
n=x.get_size();
for(int i=0;i<n;i++){
(*this).insert_tail(x[i]);
}
return *this; //ritorna la cosa cui sta puntando this
};
void ordina(){
//vettore<T>*new_this=this;
vettore<T>*aux=this;
vettore<T>*punt_a_min=aux;
bool sentinella=0;
T min=aux->get_my();
while(aux->get_next()!=nullptr){
aux=aux->get_next();
if(aux->get_my()<min){
sentinella=1;
min=aux->get_my();
punt_a_min=aux;
}
}
if(sentinella==1){
punt_a_min->set_obj(this->get_my());
this->set_obj(min);
}
if(this->get_next()!=nullptr) *(this->get_next()).ordina();
};
void set_next(vettore<T>*e){
next=e;
}
void set_obj(T obj){
my_object=obj;
};
void order(){
unsigned int n=(*this).get_size();
if(n==2){
T * p=new T;
p[0]=next->get_my();
next->set_obj(my_object);
my_object=p[0];
}
if(n>2){
T * p=new T[n];
vettore<T> * aux=this;
for(unsigned int i=0;i<n;i++){
p[i]=aux->get_my();
aux=aux->get_next();
//I++
}
aux=this;
for(unsigned int i=0;i<n-1;i++){
aux=aux->get_next();
aux->set_obj(p[i]);
}
this->set_obj(p[n-1]);
delete []p;
}
};
void append(T obj){
vettore<T> * aux=this;
while(aux->get_next()!=nullptr) aux=aux->get_next();
aux->set_next(new vettore <T>); //lo faccio puntare da aux->next al posto di nullptr ~ next=&v
aux=aux->get_next();
aux->set_obj(obj);
aux->set_next(nullptr);
};
void insert_tail(T obj){
vettore<T> * aux=this;
while(aux->get_next()!=nullptr) aux=aux->get_next();
aux->set_next(new vettore <T>);
aux=aux->get_next();
aux->set_obj(obj);
aux->set_next(nullptr);
};
void remove_tail(){
vettore<T> * aux=this;
while(aux->get_next()->get_next()!=nullptr) aux=aux->get_next();
delete aux->get_next();
aux->set_next(nullptr);
};
unsigned int get_size(){
if(this==nullptr) return 0;
if(this->next==nullptr) return 1;
return 1+(*(this->next)).get_size();
};
bool has_sense(){
return 1;
};
T& operator[](unsigned int n){
if(this->get_size()-1<n) std::cout<<"elemento non accessibile"<<std::endl;
if(n==0) return my_object;
else{
vettore<T> * aux=this;
for(int ii=0;ii<n;ii++) aux=aux->get_next();
return aux->get_obj();
}
};
};
class car {
protected:
int i;
int j;
bool bloc;
public:
car():i(-1),j(-1),bloc(0){}; //default constructor
car(int i,int j,bool bloc):i(i),j(j),bloc(bloc){}; //first constructor
car(int i,int j):i(i),j(j),bloc(0){}; //second constructor
car(const car & un_altro):i(un_altro.i),j(un_altro.j),bloc(un_altro.bloc){}; //copy constructor
virtual ~car(){}; //destructor
car &operator=(const car &x){
i=x.i;
j=x.j;
bloc=x.bloc;
return *this;
};
void set_i(int a){
i=a;
};
void set_j(int b){
j=b;
};
void set_bloc(bool c){
bloc=c;
};
void set_2(int a, int b){
i=a;
j=b;
};
void set_3(int a, int b,bool c){
i=a;
j=b;
bloc=c;
};
int get_i(){
return i;
};
int get_j(){
return j;
};
bool get_bloc(){
return bloc;
};
//print
bool has_sense(){
return(i>=0 && j>=0);
};
virtual void print(){
std::cout<<"Questa car si trova in posizione ("<<i<<","<<j<<") ed è "<<bloc<<"*bloccata"<<std::endl;
};
};
class red_car:public car{
public:
red_car():car(){};
red_car(int i,int j, bool bloc):car(i,j,bloc){};
red_car(int i, int j):car(i,j){};
red_car(const red_car & un_altro):car(un_altro){}; //copy constructor ereditato
red_car &operator=(const red_car &x){
i=x.i;
j=x.j;
bloc=x.bloc;
return *this;
};
void move_red(){
if(j>=0) j++;
bloc=0;
};
bool has_sense(){
return(i>=0 && j>=0);
};
void move_red_border(){
if(j>=0) j=0;
bloc=0;
};
};
class blue_car:public car{
public:
blue_car():car(){};
blue_car(int i,int j, bool bloc):car(i,j,bloc){};
blue_car(int i, int j):car(i,j){};
blue_car(const blue_car & un_altro):car(un_altro){}; //copy constructor ereditato
blue_car &operator=(const blue_car &x){
i=x.i;
j=x.j;
bloc=x.bloc;
return *this;
};
void move_blue(){
if(i>=0) i++;
bloc=0;
};
bool has_sense(){
return(i>=0 && j>=0);
};
void move_blue_border(){
if(i>=0) i=0;
bloc=0;
};
};
Can you please tell me what is going on?
Thank you for your time.
I think the error is in the command you use to build the project by hand:
$ g++ -O2 -std=c++11 -o output main.cpp
Instead, you need to issue the following command:
$ g++ -O2 -std=c++11 -o output main.cpp <where_move_red_and_blue_are_defined.cpp>
If the functions void move_red(/*...*/) and void move_blue(/*...*/) are defined in a source file other than main.cpp, the error you get, which is a linking error, is going to occur. The reason is, the compiler sees no definition of the functions, only the declaration, which is most likely located in a header. Thus, when the compiler sees a call to the function in the main() code, that works out fine - the declaration is enough (the declaration is found since you've included the *.hpp file into main.cpp), but when it comes to linking, i.e. joining the multiple .o object files together into a single executable, an error occurs since there is no indication as to where to find the object file where the functions are defined.

C++ : Can't pass generic function to another one as a parameter

I want to pass multiple compare functions to the selection sort function as shown below but i get the fallowing error :
Error 1 error C2664: 'sort' : cannot convert parameter 3 from 'bool (__cdecl *)(int,int)' to 'bool *(__cdecl *)(T,T)' c:\users\milad\documents\visual studio 2008\projects\functionpass\functionpass\passcompare.cpp 49 FunctionPass
Code :
bool integerCompare (int a , int b)
{
return(a<b);
}
bool charCompare (char a , char b)
{
return(a<b);
}
bool stringCompare (string a , string b)
{
if(a.compare(b)<0) return true;
else return false;
}
template <class T>
void sort(T x[], int n , bool(*whichCompare(T,T))) // n=size of the array
{
for (int pass=0; pass<n-1; pass++) {
int potentialSmallest = pass;
for (int i=pass+1; i<n; i++) {
if ((*whichCompare)(x[i],x[potentialSmallest])) {
potentialSmallest = i;
}
}
int temp = x[pass];
x[pass] = x[potentialSmallest];
x[potentialSmallest] = temp;
}
}
template <typename T>
void printArray(T a[], int size)
{
for(int i=0;i<size;i++)
cout<<" "<<a[i];
}
int main()
{
int intArray[] = {1,7,-8,-14,46,33,4};
sort <int>(intArray , 7 , integerCompare);
printArray<int>(intArray,7);
}
You have this:
template <class T> void sort(T x[], int n , bool(*whichCompare(T,T)))
{ /*...*/ }
The parameter declaration for a pointer to a function returning a bool and two arguments of type T is wrong. You probably really wanted:
template <class T> void sort(T x[], int n , bool (*whichCompare)(T,T))
{ /*...*/ }
Although typically functions like these are written like this:
template <class T, typename Functor>
void sort(T x[], int n , Functor whichCompare)
{
// ...
bool result = whichCompare(x[i], x[potentialSmallest]);
// ...
}
This way, users can not only pass in function pointers, but function objects that provides an operator()():
struct MyIntegerCompareFunctor
{
bool operator()(int a, int b) { return a < b; }
};
sort(intArray, 7, MyIntegerCompareFunctor());
sort(intArray, 7, &integerCompare); // Works too
Some of the algorithms provided by the C++ standard libraries are written like this.
See my corrections in the lines that have whichCompare in them.
template <class T>
void sort(T x[], int n , bool(*whichCompare)(T,T)) // n=size of the array
{
for (int pass=0; pass<n-1; pass++) {
int potentialSmallest = pass;
for (int i=pass+1; i<n; i++) {
if (whichCompare(x[i],x[potentialSmallest])) {
potentialSmallest = i;
}
}
int temp = x[pass];
x[pass] = x[potentialSmallest];
x[potentialSmallest] = temp;
}
}
You could also templatise the function itself thus:
template< typename T, typename Pred >
void sort( T x[], int n, Pred whichCompare )
{ // etc.
}
I used to do this initially just because it was easier but also allows functors / boost-function/boost-bind etc. to be used with your algorithm.
there is a much more sexy solution:
bool integerCompare (int a , int b)
{
return(a<b);
}
bool charCompare (char a , char b)
{
return(a<b);
}
bool stringCompare (string a , string b)
{
return (a.compare(b)<0);
}
template <typename T, size_t n >
void sort(T (&x)[n], bool whichCompare (T,T) ) // n=size of the array
{
for (int pass=0; pass<n-1; pass++) {
int potentialSmallest = pass;
for (int i=pass+1; i<n; i++) {
if (whichCompare(x[i],x[potentialSmallest])) {
potentialSmallest = i;
}
}
std::swap(x[pass], x[potentialSmallest]);
}
}
template <typename T, size_t n>
void printArray(T (&a)[n])
{
for(int i=0;i<n;i++)
cout<<" "<<a[i];
}
int main()
{
int intArray[] = {1,7,-8,-14,46,33,4};
sort (intArray, integerCompare);
printArray(intArray);
}