c++ correct use of delete after an assignment - c++

I'm a little bit confused on how to use correctly the delete keyword. Here is my scenario:
class Tuple {
public:
Tuple(int columns);
~Tuple();
void set(int i, string d);
string get(int i);
int columnCount();
private:
string *data;
int columns;
};
Tuple::Tuple(int columns) {
this->columns = columns > 0 ? columns : 0;
if (this->columns > 0) {
data = new string[this->columns];
} else {
data = 0;
}
}
Tuple::~Tuple() {
if (columns > 0) {
delete[] data;
}
}
void Tuple::set(int i, string d) {
if (columns > 0 && i > -1 && i < columns) {
data[i] = d;
}
}
class Table {
public:
Table(int columns);
~Table();
void insertTuple(Tuple t);
Tuple getTuple(int i);
int columnCount();
int rowCount();
private:
vector <Tuple> data;
int columns;
int rows;
};
Now, when I call the following code I get a segfault:
Tuple *outTuple;
outTuple = new Tuple(cCount);
for (int i=0; i<cCount; i++) {
tmpStr = string(reinterpret_cast<const char*>(sqlite3_column_text(statement, i)));
outTuple->set(i, tmpStr);
}
(*outTable)->insertTuple(*outTuple);
delete outTuple; //here I get segfault
What is wrong with my code? Is my code not well written? Can I improve it and avoid segfault?

The most likely reason is that the Tuple violates the rule of three. Specifically, you need to define a copy constructor and a copy assignment operator. Otherwise you are probably double-deleting data.
You don't show the constructor and the destructor, but memory management practices employed by Tuple look fragile. Why not use std::vector instead of a pointer?

Dynamically memory allocated variables with pointers, usually have a "container" or "owner".
In this case, the function is the main "container".
"Containtment" or "Ownership" may be transfer, example, from function to other variable, in this case, maybe "outTable".
Does the "outTable" deletes the tuple from memory ?
Are you intended to let "outTable" become the container of the tuple, and let it drop the tuple from memory, instead of the function ?
OR, do you intend that "outTable", only references the tuple, and, let the function drop the tuple from memory.
Cheers.

Related

I want to know how to pass an array of pointer objects into my constructor in C++

In my header file for my PCBTable.cpp I have this:
class PCBTable {
private:
PCB* table[];
}
In my PCBTable.cpp I am trying to create a constructor that initializes the table to a blank table of PCB objects, with the size of my parameter and it looks like this
PCBTable::PCBTable(int size) {
table = new PCB*[size];
}
However I get the error that table must be a modifiable value(E0137), and that array type PCB*[] is not assignable.
I've tried messing around with this but I can't get it to work.
new T[...] returns a T* pointer, where T in your case is PCB*, thus you are asking new[] to return a PCB** pointer, which cannot be assigned to a PCB*[] 1 fixed array, hence the error.
(1 you are not specifying the size of the array, which is invalid syntax)
You need to change your table declaration to match what new[] actually returns, eg:
class PCBTable {
private:
PCB** table;
int table_size;
public:
PCBTable(int size);
~PCBTable();
};
PCBTable::PCBTable(int size) : table_size(size) {
table = new PCB*[size];
for (int i = 0; i < size; ++i) {
table[i] = new PCB;
}
}
PCBTable::~PCBTable() {
for (int i = 0; i < table_size; ++i) {
delete table[i];
}
delete[] table;
}
Alternatively, if you just need an array of objects, rather than an array of pointers to objects:
class PCBTable {
private:
PCB* table;
int table_size;
public:
PCBTable(int size);
~PCBTable();
};
PCBTable::PCBTable(int size) {
table_size = size;
table = new PCB[size];
}
PCBTable::~PCBTable() {
delete[] table;
}
That being said, you really should be using std::vector instead of new[]/delete[] manually. And if you are using C++11 or later, use std::unique_ptr or std::shared_ptr instead of raw pointers, eg:
#include <vector>
#include <memory>
class PCBTable {
private:
std::vector<std::unique_ptr<PCB>> table;
public:
PCBTable(int size);
};
PCBTable::PCBTable(int size) : table(size) {
for (auto &elem : table) {
elem = std::make_unique<PCB>();
}
}
Or:
#include <vector>
#include <memory>
class PCBTable {
private:
std::vector<PCB> table;
public:
PCBTable(int size);
};
PCBTable::PCBTable(int size) : table(size) {
}
There seems to be some confusion here. Arrays (declared like int foo[12]) are fixed-size at compile time and can be found on the stack. If you want a dynamically sized array, a list whose size is defined at runtime and isn't necessarily known at compile time, that needs to be a pointer. If the elements you want in your array are themselves pointers, it will have to be a pointer to pointers.
class PCBTable {
private:
PCB** table;
}
PCBTable::PCBTable(int size){
table = new PCB*[size];
}
Or, better yet, you could use std::vector, which gives you all the best of both worlds.
#include <vector>
class PCBTable {
private:
std::vector<PCB*> table;
}
PCBTable::PCBTable(int size){
table.resize(size);
}
You can use std::vector any way you would use a normal array. This also provides the dual benefit of not having to store the array size in an external variable, as table.size() takes care of that for you.

Multidimensional array: operator overloading

I have a class with a multidimensional array:
it is possible to create a one, two, ..., n dimensional array with this class
if the array has n dimensions, i want to use n operator[] to get an object:
example:
A a({2,2,2,2}];
a[0][1][1][0] = 5;
but array is not a vector of pointer which lead to other vectors etc...
so i want the operator[] to return a class object until the last dimension, then return a integer
This is a strongly simplified code, but it shows my problem:
The error i receive: "[Error] cannot convert 'A::B' to 'int' in initialization"
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <iostream> // cin, cout...
class A {
private:
static int* a;
public:
static int dimensions;
A(int i=0) {
dimensions = i;
a = new int[5];
for(int j=0; j<5; j++) a[j]=j;
};
class B{
public:
B operator[](std::ptrdiff_t);
};
class C: public B{
public:
int& operator[](std::ptrdiff_t);
};
B operator[](std::ptrdiff_t);
};
//int A::count = 0;
A::B A::operator[] (std::ptrdiff_t i) {
B res;
if (dimensions <= 1){
res = C();
}
else{
res = B();
}
dimensions--;
return res;
}
A::B A::B::operator[] (std::ptrdiff_t i){
B res;
if (dimensions <=1){
res = B();
}
else{
res = C();
}
dimensions--;
return res;
}
int& A::C::operator[](std::ptrdiff_t i){
return *(a+i);
}
int main(){
A* obj = new A(5);
int res = obj[1][1][1][1][1];
std::cout<< res << std::endl;
}
The operator[] is evaluated from left to right in obj[1][1]...[1], so obj[1] returns a B object. Suppose now you just have int res = obj[1], then you'll assign to a B object (or C object in the case of multiple invocations of []) an int, but there is no conversion from B or C to int. You probably need to write a conversion operator, like
operator int()
{
// convert to int here
}
for A, B and C, as overloaded operators are not inherited.
I got rid of your compiling error just by writing such operators for A and B (of course I have linking errors since there are un-defined functions).
Also, note that if you want to write something like obj[1][1]...[1] = 10, you need to overload operator=, as again there is no implicit conversion from int to A or your proxy objects.
Hope this makes sense.
PS: see also #Oncaphillis' comment!
vsoftco is totally right, you need to implement an overload operator if you want to actually access your elements. This is necessary if you want it to be dynamic, which is how you describe it. I actually thought this was an interesting problem, so I implemented what you described as a template. I think it works, but a few things might be slightly off. Here's the code:
template<typename T>
class nDimArray {
using thisT = nDimArray<T>;
T m_value;
std::vector<thisT*> m_children;
public:
nDimArray(std::vector<T> sizes) {
assert(sizes.size() != 0);
int thisSize = sizes[sizes.size() - 1];
sizes.pop_back();
m_children.resize(thisSize);
if(sizes.size() == 0) {
//initialize elements
for(auto &c : m_children) {
c = new nDimArray(T(0));
}
} else {
//initialize children
for(auto &c : m_children) {
c = new nDimArray(sizes);
}
}
}
~nDimArray() {
for(auto &c : m_children) {
delete c;
}
}
nDimArray<T> &operator[](const unsigned int index) {
assert(!isElement());
assert(index < m_children.size());
return *m_children[index];
}
//icky dynamic cast operators
operator T() {
assert(isElement());
return m_value;
}
T &operator=(T value) {
assert(isElement());
m_value = value;
return m_value;
}
private:
nDimArray(T value) {
m_value = value;
}
bool isElement() const {
return m_children.size() == 0;
}
//no implementation yet
nDimArray(const nDimArray&);
nDimArray&operator=(const nDimArray&);
};
The basic idea is that this class can either act as an array of arrays, or an element. That means that in fact an array of arrays COULD be an array of elements! When you want to get a value, it tries to cast it to an element, and if that doesn't work, it just throws an assertion error.
Hopefully it makes sense, and of course if you have any questions ask away! In fact, I hope you do ask because the scope of the problem you describe is greater than you probably think it is.
It could be fun to use a Russian-doll style template class for this.
// general template where 'd' indicates the number of dimensions of the container
// and 'n' indicates the length of each dimension
// with a bit more template magic, we could probably support each
// dimension being able to have it's own size
template<size_t d, size_t n>
class foo
{
private:
foo<d-1, n> data[n];
public:
foo<d-1, n>& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
// a specialization for one dimension. n can still specify the length
template<size_t n>
class foo<1, n>
{
private:
int data[n];
public:
int& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
int main(int argc, char** argv)
{
foo<3, 10> myFoo;
for(int i=0; i<10; ++i)
for(int j=0; j<10; ++j)
for(int k=0; k<10; ++k)
myFoo[i][j][k] = i*10000 + j*100 + k;
return myFoo[9][9][9]; // would be 090909 in this case
}
Each dimension keeps an array of previous-dimension elements. Dimension 1 uses the base specialization that tracks a 1D int array. Dimension 2 would then keep an array of one-dimentional arrays, D3 would have an array of two-dimensional arrays, etc. Then access looks the same as native multi-dimensional arrays. I'm using arrays inside the class in my example. This makes all the memory contiguous for the n-dimensional arrays, and doesn't require dynamic allocations inside the class. However, you could provide the same functionality with dynamic allocation as well.

Creating an array of a struct

I am trying to make an array of structs, but I am getting the error no matching function for call to 'Cell::Cell()'.
Cell is the name of my struct. Here is some of my code:
struct Cell{
int number;
Cell(int n){
number = n;
}
};
class MyClass{
public:
int nCells;
void inject(){
std::cout << "Enter number:";
string in;
std::cin >> in;
int amount = in.size()/3;
Cell cells [amount]; // <-- error
int index = 0;
int t = in.size();
while (t >= 3){
cells[index] = new Cell(atoi(in.substr(t-3,3).c_str());
t -= 3;
index++;
}
}
MyClass(int n){
nCells = n;
}
};
Cell cells [amount]; is giving me the error. I am new to classes, but I know how to make arrays of primitive types. int cells [amount]; would work, for instance.
But how am I supposed to make an array of type Cell ?
Cell doesnt have a default constructor (as soon as you specify another constructor the compiler will not create a default constructor anymore). However the definition Cell cells[amount] will automatically default initialize every element.
I think the best way in this particular situation is simply to implement a default constructor:
struct Cell{
int number;
Cell() : number(0)
{
}
Cell(int n) : number(n)
{
}
};
Also notice as amount is not known at compile time, Cell cells[amount] is basically illegal. However some compilers have extensions to allow this. But its better if you heap allocate it:
Cell* cells = new Cell[amount];
Dont forget to destroy it however.
If you know how long the array is, you can use c++11 initialization. This will do :
int main()
{
Cell c[3]{ Cell(1), Cell(2), Cell(3) };
}
By the way this
Cell cells [amount];
is using VLAs, and that is not supported by c++ (only as extension for some compilers).
In c++, much better would be to use std::vector :
#include <vector>
struct Cell{
int number;
Cell(int n){
number = n;
}
};
int main()
{
int n = 5;
std::vector< Cell > c;
for ( int i =0; i < n; ++ i )
{
c.emplace_back( Cell( i ) );
}
}
By doing Cell cells [amount]; you are calling the Cell constructor, but in this case you don't have a default constructor for Cell, so you must use pointers instead, you are using them in the while stuff.
Just change
Cell cells [amount];
for
Cell* cells [amount];

Dereferencing a pointer to an object inside its class

I have SquareMatrix defined as such
SquareMatrix.h
#ifndef SQUAREMATRIX_H
#define SQUAREMATRIX_H
#include "Matrix.h"
#include <vector>
class SquareMatrix : public Matrix
{
public:
SquareMatrix();
SquareMatrix(std::vector<std::vector<long double> >);
//~SquareMatrix(); //just in case there is dynamic memory explicitly used
//convenient member functions exclusive to SquareMatrix
bool isUpperDiagonalMatrix() const;
static SquareMatrix identityMatrix(unsigned);
void LUDecompose();
SquareMatrix *Lptr, *Uptr, *Pptr; //should be initialized by LUDecompose before using
protected:
void validateData();
private:
};
#endif // SQUAREMATRIX_H
and I am trying to set Lptr, Uptr (and maybe Pptr) with a call to SquareMatrix::LUDecompose(). It is defined below:
void SquareMatrix::LUDecompose()
{
unsigned rowCount = this->getRowCount();
//initialize L to identityMatrix
*this->Lptr = SquareMatrix::identityMatrix(rowCount);
//initialize U to sparse matrix with the first row containing the sole non-zero elements
std::vector<std::vector<long double> > UData(1, this->matrixData[0]); //making first rowVector the first rowVector of this
UData.insert(UData.end(), rowCount - 1, std::vector<long double>(rowCount,0)); //making all other rowVectors zero vectors
*Uptr = SquareMatrix(UData);
// attempting to perform LU decomposition
for (unsigned j = 0; j < rowCount; j++)
{
long double pivot = Uptr->matrixData[j][j];
//the pivot should be non-zero; throwing exception that should effectively cause function to return
if (pivot == 0)
throw MatrixArithmeticException(LU_DECOMPOSITION_FAILURE);
for (unsigned k = j+1; k < rowCount; k++)
{
if (j == 0)
{
//using *this to compute entries for L,U
this->Lptr->matrixData[k][j] = (this->matrixData[k][j])/pivot; //setting columns of L
long double multiplier = this->Lptr->matrixData[k][j];
//setting row of U
for (unsigned l = k; l < rowCount; l++)
{
Uptr->matrixData[k][l] = (this->matrixData[k][l])-multiplier*(this->matrixData[0][l]);
}
}
else
{
//using U to compute entries for L,U
//same procedure as before
this->Lptr->matrixData[k][j] = (Uptr->matrixData[k][j])/pivot;
long double multiplier = this->Lptr->matrixData[k][j];
for (unsigned l = k; l < rowCount; l++)
{
Uptr->matrixData[k][l] -= multiplier*(Uptr->matrixData[0][l]);
}
}
}
}
}
Upon trying to test out this function, it throws a segmentation fault at me, with the last line being the first line where I attempt to manipulate Lptr.
I attempt to change the object pointed by Lptr, and I know that I will not be able to reference the function and set the pointer equal to that reference. In other words, my compiler (GNU GCC compiler) will not allow this->Lptr = &SquareMatrix::identityMatrix(rowCount); as it will throw an -fpermissive type error.
Note: SquareMatrix::identityMatrix(unsigned) is defined as:
SquareMatrix SquareMatrix::identityMatrix(unsigned size)
{
std::vector<long double> rowVector(size, 0L);
std::vector<std::vector<long double> > identityMatrixData;
for (int i = 0; i < size; i++)
{
//setting the rowVector to zero-one vector
rowVector[i] = 1L;
if (i > 0) rowVector[i-1] = 0L;
//pushing rowVector into identityMatrixData
identityMatrixData.push_back(rowVector);
}
return SquareMatrix(identityMatrixData);
}
What do you think you CAN do about it?
I think I have two options:
throw the object on the heap, and then try to set it with the function (that would seem useless as you are redefining the object you just defined by throwing it on the heap)
get c++11 (or something similar)
Make the function a helper function that returns a std::vector<SquareMatrix*> of size two (containing pointers to the two desired SquareMatrix values), and create a function that calls the helper function and sets Lptr, Uptr to the respective elements of the returned vector.
Are my options this limited??
*Uptr = SquareMatrix(UData); in LUDecompose() is the problem.
You cannot set the pointer to an object that is being destroyed when the function returns. Then the pointer is a dangling pointer and whenever you attempt to use it, it'll segfault.
You need to do Uptr = new SquareMatrix(UData);. Then in your destructor, call delete Uptr;.
If you have access to C++11, you can use std::unique_ptr or any pointer containers/wrappers.
Examples of your options:
#include <memory>
class Matrix
{
public:
Matrix() {}
virtual ~Matrix() {}
};
class SqMatrix : public Matrix //using raw pointers. You must remember to delete your pointers.
{
private:
SqMatrix* UPtr = nullptr;
public:
SqMatrix() : Matrix() {}
void InitPtrs() {delete UPtr; UPtr = new SqMatrix();}
~SqMatrix() {delete UPtr;}
};
class OMatrix : public Matrix //No need to worry about clean up.
{
private:
std::unique_ptr<OMatrix> OPtr;
public:
OMatrix() : Matrix() {}
void InitPtrs() {OPtr.reset(new OMatrix());}
~OMatrix() {}
};
Another option is to just store it in a vector.

Deleting templated C++ 2-dimensional array

Annoyance over C++'s requirement to pass a dimension in a 2-d array got me working on a templated Matrix class. I've been coding in C# for a bit, so I'm sure I'm a little rusty here.
Issue is, I get a heap exception as soon as I hit the destructor, which is trying to delete the 2-d array.
Any help gratefully accepted!
template <typename T>
class Matrix {
public:
Matrix(int m, int n) : nRows(m), nCols(n) {
pMatrix = new T * [nRows];
for (int i = 0; i < nCols; i++) {
pMatrix[i] = new T[nCols];
}
}
~Matrix() {
if (pMatrix != NULL) {
for (int i = 0; i < nRows; i++) { delete[] pMatrix[i]; }
delete[] pMatrix;
}
}
T ** GetMatrix() const { return pMatrix; }
T * Row(int i) const { return pMatrix[i]; }
inline T Cell(int row, int col) const { return pMatrix[row][col]; }
inline int GetNRows() const { return nRows; }
inline int GetNCols() const { return nCols; }
private:
int nRows, nCols;
T ** pMatrix;
};
This is the bug:
for (int i = 0; i < nCols; i++) {
pMatrix[i] = new T[nCols];
}
The loop should be until nRows, not nCols.
Other than that, let me tell you about something I did when I got tired of allocating 2-d arrays. I had to do a 3-d array. I used a map, that mapped from a coordinate - a struct holding x, y, z to the type I wanted.
I worked fast, and no need to allocate or deallocate. Assigning to a coordinate was simply done by
mymap[Coord(x, y, z)] = whatever...
Of course I needed to define the Coord struct and overload the < operator, but I found that way more comvenient than trying to allocate and deallocate a 3-d array.
Of course you will need to check if this scheme is fast enough for you. I used it to draw cells within a big cube using OpenGL and had no complaints at all.
Concerning the bug, #CodeChords_man explained it right. I have notes on implementation. I recommend to look through this wonderful FAQ post.
You should not use dynamic memory allocation unless you are 100% sure that
You really need it
You know how to implement it
I don't know of the first, and how the performance is crucial for you. But as for the second, you at least violated the rule of three. You class is very unsafe to use. If you copy it, the memory buffer will then be double-deleted.
You should not afraid to used STL containers, they are fast and optimized. At least the std::vector, it is as fast as the raw pointer in many scenarios. You can rewrite you class using std::vector as follows:
template <typename T>
class Matrix {
public:
typedef std::vector<T> MatrixRow;
typedef std::vector<MatrixRow> MatrixBody;
Matrix(int m, int n) : nRows(m), nCols(n), _body(m, MatrixRow(n)) {}
const MatrixBody& GetMatrix() const { return _body; }
const MatrixRow& GetRow(int i) const { return _body[i]; }
inline T Cell(int row, int col) const { return _body[row][col]; }
inline int GetNRows() const { return nRows; }
inline int GetNCols() const { return nCols; }
private:
int nRows, nCols;
MatrixBody _body;
};
Since this class is not using dynamic memory allocation, it is safe to copy and assign. You also don't need to explicitly store nRows and nCols in this case; you can use _body.size() and _body[0].size() instead.
Concerning underlying vector of vectors, it is dereferenced using the same [i][j] construction. It is easily iterated with begin() and end(). And if you absolutely need to use the raw pointer in some routine, you can always access it with &row[0].
The only possible difficulty is that you cannot easily convert MatrixBody to T**. But think it twice, maybe you don't really need to use T** at all.