How to delete a dinamically allocated struct? (c++) - c++

(About a hour ago I asked something about my code and accidentally deleted the post instead of editing it. I'm sorry for those who kindly answered to me. However, since I edited my code and partially fixed the issue, I'd rather ask for the new deal here.)
I have a class, and I have a struct inside my class. Since I want to be able to print its content, I overloaded the ostream operator:
struct packetarray {
const value_type *pktarr;
positive length;
packetarray() : pktarr(0), length(0) {}
packetarray(value_type *v, positive l) : pktarr(v), length(l) {}
~packetarray() {
delete[] pktarr;
pktarr = 0;
length = 0;
}
friend std::ostream &operator<<(std::ostream &os, const packetarray &p) {
os << "[ ";
for (int j = 0; j < p.length; ++j) {
os << p.pktarr[j];
if (j < (p.length - 1)) {
os << ",\t";
}
}
os << " ]";
return os;
}
};
with value_type being typedef T for my template class.
I have a method, packet, which returns a packetarray object:
packetarray* packet(positive y, positive x) {
try {
if (y >= this->y || x >= this->x) {
throw OutOfBounds();
}
value_type *v = new value_type[this->z];
for (int z = 0; z < this->z; z++) {
v[z] = this->operator()(z, y, x);
}
packetarray *p = new packetarray(v, this->z);
v = 0;
return p;
}
catch (const OutOfBounds &e) {
std::cout << e.message() << std::endl;
packetarray *p = new packetarray();
return p;
}
}
As you can see, when I write value_type *v = new value_type[this->z] I allocate memory on the heap, memory which is later supposed to be freed. However, since this memory is shared with the pktarr pointer of my packetarray struct, I can't free the memory unti I safely returned (and printed) the content of my packetarray object.
My intention (expectation?) was to delete that part of memory in the packetarray destructor -- but even if I actually create a packetarray object on the heap by writing packetarray *p = new packetarray(v, this->z), no destructor is being called at the end of the program. So, how am I supposed to free the memory I need to allocate in order to initialize my packetarray object?
(For those who are wondering what my class does: it's basically a 3-dimentional array and the packet method returns a data structure which contains all the elements at a certain (y, x) position for every plane z.)

Related

how return different types from function in c++?

I have a homework in c++ to make a Vector for multi data types in the same vector, I stuck where I need to return different data types and I can't change the main.
The homework ask to make the main valid:
int main()
{
Vector v;
v.add(5);
v.add(5.5f);
v.add("this");
for (int i = 0; i != v.size(); ++i) { // this code print 5 5.5 this
std::cout << v.get(i) << "\t";
}
std::cout << "Displaying an object of type Vector in different way:\n";
Integer x;
x = v.get(0);
std::cout << x << "\t"; // it prints 5
Float y;
y = v.get(1);
std::cout << y << "\t"; // it prints 5.5
String z;
z = v.get(2);
std::cout << z << "\t"; // it prints this
}
I tried what I know and I got 3 ways but still didn't fix that first I made all data pointer is char* and made a string type that worked with saving the data and cout but it stuck on return data type, I cant use template because I'm not allowed to change the main
int get(int n)
{
Node* p = head;
int i;
for (i = 0; (i < n)&&p->next; i++)
p = p->next;
if (i != n)
return NULL;
if (p->type != "int")
return NULL;
else return *((int*)p->data);
}
still I cant overload functions by just the return type, I tried to make vector have 3 pointers to data but still I stuck
int* int_;
float* float_;
string* string_;
Node* next;
string type;
Node(string type_)
I searched on internet and still not found what I want, at last I tried to make the Node template
but since the get function is on the vector and the main didn't send a type that's didn't solve the problem.
You might return wrapper with conversion operator, something like:
struct data
{
int int_ = 0;
float float_ = 0;
string string_;
operator int () const { return int_; }
operator float () const { return float_; }
operator std::string () const { return string_; }
};
const Node* get_node(int n) const
{
Node* p = head;
int i;
for (i = 0; (i < n) && p->next; i++)
p = p->next;
return p;
}
data get(int n) const
{
auto* node = get_node(n);
if (node == nullptr) throw std::out_of_range{};
return node->data;
}
Demo
If I understood correctly, what you are looking for is an heterogeneous container.
You need to create a wrapper that handle different types transparently inside your container. For your underlying type you have several options depending on your necessity.
If you know upfront the list of types that you need to support at compile type, you can use std::variant https://en.cppreference.com/w/cpp/utility/variant.
If the types that you need to support are unbounded at compile time you can use https://en.cppreference.com/w/cpp/utility/any
Finally, you can create a common interface and implement a wrapper for your supported types. The container will store a smart pointer of your objects.
UPDATE
removed suggestion on designed decision based on the C++ version
removed reference to std::vector

2D Array of Pointers -> Classes

I am having problems with my constructor in class World.
I created a 2D array with pointers where each entry in the array is of type Organism, hence the line of code:
Organism* grid[20][20];
When I run my program, I only see
hello
and after that, I get a message saying that my program has stopped working. I'm pretty sure it's the line of code
grid[i][j]->symbol = ' ';
that's causing the problem. Just to see what would happen, I changed that line to
grid[i][j];
and didn't get any errors. But, the moment I put ->, I seem to get errors.
Is there a reason why my program stops working after I put ->? Any help would be appreciated.
This is my code:
#include <iostream>
using namespace std;
class Organism
{
public:
char symbol;
};
class World
{
public:
World();
private:
Organism* grid[20][20];
};
int main()
{
World world;
return 0;
}
World::World()
{
for(int i = 0; i < 20; i++)
for(int j = 0; j < 20; j++)
{
cout << "hello" << endl;
grid[i][j]->symbol = ' ';
cout << "here" << endl;
}
}
You have an array of pointers to Organism.
Pointers can not hold any data other than an address. They can only point to memory (that holds data).
Your array's pointers does not point to anything, thats why you get undefined behaviour when you try to assign data to where the pointers point at.
You need to allocate memory for your array.
Organism grid[20][20]; // Create an array of objects (not pointers).
/* ... */
grid[i][j].symbol = ' ';
Same using dynamic memory:
class World {
public:
World();
~World(); // Rule of Three.
World(const World&) = delete; // Rule of Three.
World& operator=(const World&) = delete; // Rule of Three.
private:
Organism** grid;
};
World::World() {
grid = new Organism*[20]; // Allocate memory to point to.
for(std::size_t i = 0; i != 20; ++i) {
grid[i] = new Organism[20]; // Allocate memory to point to.
for(std::size_t j = 0; j != 20; ++j) {
cout << "hello" << endl;
grid[i][j].symbol = ' ';
cout << "here" << endl;
}
}
}
// Destructor needed to deallocate memory (otherwise it will leak).
World::~World()
{
for (std::size_t i = 0; i != 20; ++i) {
delete[] grid[i];
}
delete[] grid;
}
Now you can see how complicated it gets when using dynamic memory and why it's recommended to prefer to use automatic storage duration (i.e. create objects, not pointers and new/delete).
Even better is to use a container from the standard library for storing your elements as e.g. std::vector.
Related:
What is The Rule of Three?
Change
Organism* grid[20][20];
To
Organism grid[20][20];
and use
grid[i][j].symbol = '';
instead of
grid[i][j]->symbol = '';
and add a default constructor to Organism
class Organism
{
Organism();
...
}
or make Organism a struct
struct Oranism
{
...
}

How can I do to get correct output in class?

This is the default constructor with no parameters. By default, this allocates space for a
double array of size 10 and assigns a default value of 0 to each of them.
its a ""class"" , I m not sure what i m doing right or wrong..
I fill the public body functions , but my output is nothing suppose to print 0000000000
, I m very new to coding.
class DataVector
{
private:
DataType *m_data;//Pointer to dynamically allocated memory that holds all items
UIntType m_size;//Size of the m_data array
public:
DataVector()
{
double *m_data = new double[m_size];
for (int i = 0; i < m_size; i++)
{
*m_data = 0;
m_data++;
}
}
void PrintItems()
{
for (int i = 0; i < m_size; i++)
{
cout << *m_data << " ";
m_data++;
}
}
};
void TestDataVector()
{
{
DataVector d1;
d1.PrintItems();
}
}
There are a few problems with this implementation of yours:
You are not initializing m_size
You change the value of the pointer m_data which is supposed to hold the address of first member of the array. So, at the end of the initializer, m_data is pointing to a spot one after the block you had allocated by new.
same in the printItems member function, but here the pointer already points to an invalid location.
Also, because you are allocating memory in the constructor, you should also define a destructor to free that memory.

union of 2 sets; return simple object - C++

What is the best way to implement the following? I am trying to find the union of 2 sets. I am creating 2 objects (one called set1 and one called set2). I aim to create a 3rd object that is a UNION of the two without having to use a copy constructor. Using dynmanic memory allocation and pointers and/or references is a must. Thanks to anyone to solves this dilemma and any pointers (no pun intended) would help.
Thanks coders.
THE HEADER file
#ifndef INTEGERSET_H_
#define INTEGERSET_H_
class IntegerSet
{
private:
int * set;
int set_size;
public:
IntegerSet(int size); //default constructor
~IntegerSet(); //destructor
IntegerSet * unionOfSets(const IntegerSet & set2);
void insertElement(int k) const;
void printSet(int size) const;
};
#endif
THE MAIN file
#include <iostream>
#include "integerset.h"
using std::cout;
using std::endl;
int main()
{
IntegerSet set1(11);
//testing below
set1.insertElement(3);
set1.insertElement(4);
set1.insertElement(6);
set1.insertElement(10);
set1.printSet(11);
cout << endl;
IntegerSet set2(8);
set2.insertElement(3);
set2.insertElement(6);
set2.insertElement(7);
set2.printSet(11);
cout << endl;
IntegerSet * obj3 = new IntegerSet(11);
obj3 = set1.unionOfSets(set2);
obj3->printSet(11);
// system("pause");
return 0;
}
THE IMPLEMENTATION FILE
#include "integerset.h"
#include <iostream>
IntegerSet::IntegerSet(int size)
{
set = new int[size];
set_size = size;
for (int i = 0; i < size; i++)
set[i] = 0;
}
IntegerSet::~IntegerSet()
{
delete [] set;
}
void IntegerSet::insertElement(int k) const
{
(*this).set[k] = 1;
}
void IntegerSet::printSet(int size) const
{
int temp = 0;
for (int i = 0; i < size; i++)
{
if (set[i] == 1)
{
std::cout << i << " ";
temp++;
}
}
if (temp == 0)
std::cout << "----";
}
IntegerSet * IntegerSet::unionOfSets(const IntegerSet & set2) //make this return the union of 2 sets; THIS and the passed ARG reference; return address
{
return this;
}
Random morning rant
What you try to create is more a std::bitset than a std::set. A set is usually "a collection of well defined distinct objects" (Cantor's definition is a little bit more complex, but lets stick to this). As such, a set could contain several pairwise unrelated objects.
Now, after this has been said, have a look at std::bitset. Note that its size is fixed by the template parameter N. std::bitset::set is almost equivalent to your IntegerSet::insertElement, except that it throws std::out_of_range. This I recommend you to check your index for valid position:
void IntegerSet::insertElement(int k) const
{
if( k < 0 || k >= set_size)
throw std::out_of_range;
else
this->set[k] = 1;
}
However, std::bitset doesn't support unions, so it's time to address your meain conern.
IntegerSet::unionofSets
Have a look at those lines.
IntegerSet * obj3 = new IntegerSet(11);
obj3 = set1.unionOfSets(set2);
The first line initializes obj3 with a pointer which contains the memory for a newly created IntegerSet with an internal set of size 11. And in the next line, your throw that pointer away. So you're throwing away resources and create a memory leak.
If you were to create a new IntegerSet your solution would be quite simple:
IntegerSet IntegerSet::unionOfSets(const IntegerSet & set2) const
{
IntegerSet tmp (std::max(set2.set_size, this->set_size));
for(int i = 0; i < set_size; ++i)
tmp.set[i] = this->set[i];
for(int i = 0; i < set2.set_size; ++i)
tmp.set[i] |= set2.set[i];
return tmp;
}
But your implementation changes the object it has been called from, so it isn't const and a little bit different:
IntegerSet * IntegerSet::unionOfSets(const IntegerSet & set2) // not const!
{
if(set2.set_size > set_size){
// the resulting set is bigger, we need new memory
int * newset = new int[set2.set_size];
// copy old values
for(int i = 0; i < this->set_size; ++i)
newset[i] = this->set[i];
// replace old size
this->set_size = set2.set_size;
delete[] this->set; // remove old data
this->set = newset; // replace pointer
}
for(int i = 0; i < set2.set_size; ++i)
this->set[i] |= set2.set[i];
return this;
}
This should be sufficient. Keep in mind that you must not use new IntegerSet in order to create a union:
IntegerSet * obj3 = new IntegerSet(11); // new memory, lets say obj3 = 0x500a
obj3 = set1.unionOfSets(set2); // new memory gone forever
if(obj3 == &set1)
std::cout << "obj3 is a pointer to set1, changes to obj3 will affect set1" << std::endl;
If you don't want to create this behaviour use the first version with the temporary.
Also, please check whether std::set<int> is sufficient for you, as you can use std::set_union from <algorithm>.
EDIT
Provide a unionOfSets member function that creates a third IntegerSet that is the union of two existing IntegerSet instances (so the third set created by this function contains all the members in the two sets used to create it – so if one or both of the sets the union is performed on has an element in it, the third set will have that element)
In this case forget about IntegerSet * IntegerSet::unionOfSets(const IntegerSet&) and use IntegerSet IntegerSet::unionOfSets(const IntegerSet&) const (the first variant with a returned object instead of a returned pointer).
EDIT2
As you didn't follow the rule of three, the memory in the returned IntegerSet will be invalid. You would either have to implement a copy constructor/assignment operator in order to fix this, or provide a new object with dynamic storage duration (new). For this you would just have to adjust the method a little bit:
IntegerSet * IntegerSet::unionOfSets(const IntegerSet & set2) const
{
IntegerSet * tmp = new IntegerSet( set2.set_size > this->set_size ? set2.set_size : this->set_size);
for(int i = 0; i < set_size; ++i)
tmp->set[i] = this->set[i];
for(int i = 0; i < set2.set_size; ++i)
tmp->set[i] |= set2.set[i];
return tmp;
}
Using standard facilities...
std::vector is better than a hand-rolled array
std::sort and std::unique are goodness
Therefore:
std::vector<int> set1;
set1.push_back(1); // ... and others
std::sort(set1.begin(), set1.end()); // sorts
std::unique(set1.begin(), set1.end()); // removes duplicates
// same with set2
std::vector<int> set3(set1);
set3.insert(set3.end(), set2.begin(), set2.end());
std::sort(set1.begin(), set1.end()); // sorts
std::unique(set1.begin(), set1.end()); // removes duplicates

Access pointer array / through another pointer and delete single element in array without deleting first pointer or whole array

In my Main Window I create an instance of PointerClass, which holds an array of pointers to PointerObject (I want to be able to access it with PointerObject[X][Y] and delete it the same way, and check if PointerObject[X][Y] == NULL (which is WHY I use pointers)) and I don't want a solution with vectors.
#define X 10
#define Y 10
class PointerObject
{
public:
int X;
int Y;
}
class PointerClass
{
public:
PointerObject *ArrayOfPointerObjects[X][Y];
}
PointerMethod(&PointerClass);
Then, in my PointerMethod I create the Pointer to an array:
PointerMethod(PointerClass *pointerClass)
{
// don't know the right way to do this
pointerClass->ArrayOfPointerObjects= new PointerObject[X][Y];
// set all pointers in the array to NULL - is this needed?
for (int x=0; x < X; x++)
{
for (int y=0; y < Y; y++)
{
pointerClass->ArrayOfPointerObjects[x][y] = NULL;
}
}
// trying to store some data here
pointerClass->ArrayOfPointerObjects[0][0] = new PointerObject;
// trying to delete it
delete pointerClass->ArrayOfPointerObjects[0][0];
// or trying this:
delete[] pointerClass->ArrayOfPointerObjects[0][0];
// causes access violation or doesn't work
}
I earlier asked this without success or questions about the wrong type.
Delete pointer to multidimensional array in class through another pointer - how?
I can access the array, check if it's NULL. but when I call delete / delete[] pointerClass->ArrayOfPointerObjects[x][y] it seem to delete the pointer to pointerClass instead of the element at [X][Y] and I want to delete the pointer at location [X][Y] and not the pointerClass and I don't want to delete the whole array.
How can I do this without complicating it too much? I guess my array isn't truely an array of pointers, just a pointer to an array. But I want it to be an array of pointers stored in a pointer or something. Still the importance is how I access it and how I delete the elements in the array. I need to be able to check if the pointer is NULL and if not be able to Delete that single PointerObject.
The importance of this is that I want to:
Access the array of PointerObjects with [X][Y]
Check if an object in the array is NULL (=needs pointers)
Delete a single item in the array of pointers without destroying the pointer to the PointerClass object or deleting the rest of the array. Just delete a single PointerObject at a certain X, Y location in the array so that [X][Y] after deletion = NULL.
If there's too much confusion or likeness with my other thread it is because people told me thing I had no wish for and it led off subject, here it is better illustrated how it works and how I want it to work like.
hmm, i think something like this
#include <iostream>
class Foo
{
int i_;
int j_;
public:
Foo(int i, int j) : i_(i), j_(j) {}
void print_coords()
{
std::cout << this << " (" << i_ << ',' << j_ << ')' << std::endl;
}
};
class Bar
{
public:
Foo *arr[5][5];
};
class Que
{
public:
void init(Bar *b)
{
for(int i=0; i<5; i++)
for(int j=0; j<5; j++)
b->arr[i][j] = new Foo(i, j);
}
void print(Bar *b, int i, int j)
{
try {
if(b->arr[i][j])
b->arr[i][j]->print_coords();
else
throw 0;
} catch (int e) {
std::cout << &b->arr[i][j] << " points to null" << std::endl;
}
}
void rem(Bar *b, int i, int j)
{
delete b->arr[i][j];
b->arr[i][j] = 0;
}
};
int main()
{
Bar *b = new Bar();
Que *q = new Que();
q->init(b);
q->print(b, 2, 2);
q->rem(b, 2, 2);
q->print(b, 2, 2);
return 0;
}