I need to save objects as pointers in dynamic array but i have problem.
This is my code, there are three classes and i need to have array (arrayoftwo) of poiters to class Two that would work further with class Three and so on. I have two problems. One is that i cant figure out how to dynamically allocate space for my arrayoftwo (which i need to dynamically resize by number of stored pointers) and second problem is how to exactly store pointers to objects without destroying object itself.
Here is my code:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
class One {
public:
bool addTwo(int a);
private:
void getspace(void);
class Two {
public:
int a;
private:
class Three {
/*...*/
};
Three arrayofThree[];
};
int freeindex;
int allocated;
Two *arrayoftwo[];
};
void One::getspace(void){
// how to allocate space for array of pointers ?
arrayoftwo=new *Two[100];
allocated=100;
}
bool One::addTwo(int a){
Two temp;
temp.a=a;
getspace();
arrayoftwo[freeindex]=&temp;
freeindex++;
return true;
//after leaving this method, will the object temp still exist or pointer stored in array would be pointing on nothing ?
}
int main() {
bool status;
One x;
status = x . addTwo(100);
return 0;
}
Thank you for any help.
EDIT: I cant use vector or any other advanced containers
temp will not exist after leaving addTwo; the pointer you store to it is invalid at that point. Instead of storing the object as a local variable, allocate it on the heap with new:
Two* temp = new Two();
To allocate an array of pointers:
Two** arrayoftwo; // declare it like this
// ...
arrayoftwo = new Two*[100];
And getspace should either be passed a (from addTwo) or a should be stored as the member variable allocated and getspace should access it from there. Otherwise it's assuming 100.
Related
Today i went back and investigated an error i got in an old project. It's not exactly an error, rather, i don't know how to do what i need to do. Don't really want to go into the details of the project as it is old and buggy and inefficient and more importantly irrelevant. So i coded a new sample code:
#include <iostream>
#include <vector>
#include <time.h>
#include <random>
#include <string>
class myDoc;
class myElement
{
int myInt;
std::string myString;
myElement * nextElement;
//a pointer to the element that comes immediately after this one
public:
myElement(int x, std::string y) : myInt(x), myString(y){};
friend myDoc;
};//an element type
class myDoc
{
std::vector<myElement> elements;
public:
void load();
~myDoc()
{
//I believe i should delete the dynamic objects here.
}
};// a document class that has bunch of myElement class type objects as members
void myDoc::load()
{
srand(time(0));
myElement * curElement;
for (int i = 0; i < 20; i++)
{
int randInt = rand() % 100;
std::string textInt = std::to_string(randInt);
curElement = new myElement(randInt,textInt);
//create a new element with a random int and its string form
if (i!=0)
{
elements[i-1].nextElement = curElement;
//assign the pointer to the new element to nextElement for the previous element
//!!!!!!!!!!!! this is the part that where i try to create a copy of the pointer
//that goes out of scope, but they get destroyed as soon as the stack goes out of scope
}
elements.push_back(*curElement);// this works completely fine
}
}
int main()
{
myDoc newDoc;
newDoc.load();
// here in newDoc, non of the elements will have a valid pointer as their nextElement
return 0;
}
Basic rundown: we have a document type that consists of a vector of element type we define. And in this example we load 20 random dynamically allocated new elements to the document.
My questions/problems:
When the void myElement::load() function ends, the pointer and/or the copies of it goes out of scope and get deleted. How do i keep a copy that stays(not quite static, is it?) at least until the object it points to is deleted?
The objects in the elements vector, are they the original dynamically allocated objects or are they just a copy?
I allocate memory with new, how/when should i delete them?
Here is a picture i painted to explain 1st problem(not very accurate for the specific example but the problem is the same), and thank you for your time.
Note: I assumed you want a vector of myElement objects where each one points to the element next to it. It is unclear if you want the objects in elements to point to copies of them, anyway it should be pretty easy to modify the code to achieve the latter
This is what happens in your code:
void myDoc::load()
{
..
curElement = new myElement(n,m); // Create a new element on the heap
...
// If this is not the first element we inserted, have the pointer for the
// previous element point to the heap element
elements[i-1].nextElement = curElement;
// Insert a COPY of the heap element (not the one you stored the pointer to)
// into the vector (those are new heap elements copied from curElement)
elements.push_back(*curElement);// this works completely fine
}
so nothing gets deleted when myDoc::load() goes out of scope, but you have memory leaks and errors since the pointers aren't pointing to the elements in the elements vector but in the first heap elements you allocated.
That also answers your second question: they're copies.
In order to free your memory automatically, have no leaks and point to the right elements you might do something like
class myElement
{
int a;
std::string b;
myElement *nextElement = nullptr;
//a pointer to the element that comes immediately after this one
public:
myElement(int x, std::string y) : a(x), b(y){};
friend myDoc;
};//an element type
class myDoc
{
std::vector<std::unique_ptr<myElement>> elements;
public:
void load();
~myDoc()
{}
};// a document class that has bunch of myElement class type objects as members
void myDoc::load()
{
srand((unsigned int)time(0));
for (int i = 0; i < 20; i++)
{
int n = rand() % 100;
std::string m = std::to_string(n);
//create a new element with a random int and its string form
elements.emplace_back(std::make_unique<myElement>(n, m));
if (i != 0)
{
//assign the pointer to the new element to nextElement for the previous element
elements[i - 1]->nextElement = elements[i].get();
}
}
}
Live Example
No need to delete anything in the destructor since the smart pointers will be automatically destroyed (and memory freed) when the myDoc element gets out of scope. I believe this might be what you wanted to do since the elements are owned by the myDoc class anyway.
I'm trying to assign a node to a pointer along an array of pointers but it keeps telling me that my array was not declared in the scope. I'm totally confused on how or why so any help would be greatly beneficial! Thanks for taking the time to respond!
#include <iostream>
#include "book.h"
using namespace std;
class bookstore
{
private:
int amount = 5;
int counting = 0;
public:
bookstore()
{
bookstore *store;
store = new book*[amount];
for(int i = 0; i < amount; i++)
{
store[i] = NULL;
}
}
~bookstore(){ delete[] store; }
void addbook(string a,string b, string c, string d, string e)
{
if (counting == amount)
{
cout<<"Full House!"<<endl;
return;
}
store[counting] = new book(a,b,c,d,e);
counting++;
}
void print()
{
for(int i = 0; i < amount; i++)
{
cout<<store[i]->name<<" "<<store[i]->publisher<<" "<<store[i]->year<<" "<<store[i]->price<<" "<<store[i]->category<<endl;
}
}
};
Your pointer store is local to the default constructor. It looks like you're after a data member. Furthermore, you seem to be after an array of pointers. If so, you need bookstore needs to be a pointer to pointer:
class bookstore
{
private:
bookstore** store; // or bookstore* store
int amount = 5;
int counting = 0;
and fix the constructor to use that:
bookstore()
{
store = new book*[amount]; // or store = new book[amount]
....
Note that your class is attempting to manage dynamically allocated resources, so you will need to take care of the copy constructor and assignment operators (either make the class non-copyable and non-assignable, or implement them. The defaults are not acceptable. See the rule of three.) If you are really using an array of dynamically allocated pointers, then you need to fix your destructor too. Currently, it only deletes the array, but not the objects pointed at by the pointers in it.
The better solution would be to use a class that manages the resources for you and has the desired semantics. It is easier to have each class handle a single responsibility.
I have this small program as i am trying to understand the vector and the classname being passed as an argument. Here is the program:
#include<iostream>
#include<vector>
using namespace std;
class objectclass{
public:
void vec_try(){
cout<<"print out something";
}
};
class another{
public:
void run();
vector<objectclass *>ports;
void add_obj(objectclass *p){
ports.push_back(p);
}
};
void another::run(){
//int j=0;
ports[j]->vec_try();
}
int main(){
another a;
a.run();
system("pause");
return 0;
}
i have idea that passing classname in vector as an object is fine and then using push_back to insert the element in that vector but in the function add_obj(objectclass *p) how do i pass the values if i dont want to change the defination of the function. i know a way like this:
objectclass *p;
p= new objectclass[10];
but my function has already defination and also i want to call the function vec_try() with ports[i] so i am not getting how to pass the values and the how this is working with ports[i]. i basically need some clarification on this.
Your add_obj function takes pointers to objectclass objects. So to add elements to your vector, you need to do:
another a;
objectclass obj1; // Create an objectclass
a.add_obj(&obj1); // Pass its address to add_obj
objectclass obj2;
a.add_obj(&obj2);
objectclass obj3;
a.add_obj(&obj3);
Of course, your vector is keeping pointers to these objects. When these objects go out of scope and are destroyed, these pointers will be left pointing at invalid object. But that doesn't matter here, because your objects are only destroyed at the end of main.
An alternative would be to dynamically allocate your objects:
another a;
a.add_obj(new objectclass());
a.add_obj(new objectclass());
a.add_obj(new objectclass());
Each line dynamically allocates an objectclass object, then passes a pointer to that object to add_obj. However, you will need to make sure that you eventually delete this objects in some way or another.
The first element that you push_back into the vector will have index 0, the second will have index 1, the third will have index 2, and so on.
If in run, you want to iterate over all objects in the vector, you can do it something like this:
for (int i = 0; i < ports.size(); i++) {
ports[i]->vec_try();
}
As you can see, this loops through all the elements in the vector (from 0 to ports.size()) and calls vec_try on each one.
There is a better way to do this using iterators, but I'll leave that for a future lesson.
I am computing properties of boundary layer flow through a duct. I have a class CChannel which stores geometry of the duct, CFlow which holds global properties of the fluid and CNode which stores local parameters of the boundary layer.
When I execute the program in the current form the first element of the GridPoints vector (variable "alpha") inside CChannel is assigned the same memory location as Uinf which is a private member of the CFlow class. When I change the latter class so that the fields it holds are no longer pointers but regular variables the problem disappears. I also tried reserving memory space for the GridPoints vector inside the class constructor but without any effect. When I was searching for the answer I found that this may have been caused by the in-built code optimiser but didn't manage to learn anything else. (If this is so, how can I get around this without losing efficiency?)I am guessing the problem arises because of the differences between two different memory allocation modes (heap vs stack). I would still like to find out why is this happening exactly so I can store the global flow parameters as pointers and avoid this problem in the future.
Program.cpp
#include <iostream>
#include "Channel.h" // stores the channel geometry
#include "Flow.h" // stores the fluid properties and free stream data
#include "Node.h" // holds the local BL flow properties, e.g. BL thickness, lambda, etc.
using namespace std;
int main(void)
{
int NoNodes=21;
CChannel MyChan(4, 1.2, .8); // L, h1, h2
MyChan.MeshUniform(NoNodes);
CFlow Flow1(.5,1.529e-5,1.19); // Uinf, niu, ro
for (int i=0;i<NoNodes;i++)
{
MyChan.GridPoints->at(i).GetAlpha();
}
return(0);
}
Node.h
#pragma once
class CNode
{
public:
double *alpha, *x, *lambda; // properties dependent on the Pollhausen velocity profile
CNode(void);
~CNode(void);
void GetAlpha(void); // calculates alpha
};
Node.cpp
#include "Node.h"
#include <iostream>
CNode::CNode(void)
{
alpha=new double;
lambda=new double;
*lambda=0;
}
CNode::~CNode(void)
{
delete alpha, x, lambda;
}
void CNode::GetAlpha(void)
{
*alpha=(.3-*lambda/120.);
}
Flow.h
#pragma once
class CFlow
{
private:
double *Uinf, *niu, *ro;
public:
CFlow(double, double, double);
~CFlow(void);
};
Flow.cpp
#include "Flow.h"
CFlow::CFlow(double u, double visc, double den)
{
Uinf=new double;
niu=new double;
ro=new double;
*Uinf=u; // free stream velocity (assumes the inflow is parallel to the channel's CL) [m/s]
*niu=visc; // kinematic viscosity of the fluid [m^2/s]
*ro=den; // density of the fluid [kg/m^3]
}
CFlow::~CFlow(void)
{}
Channel.h
#pragma once
#include <vector>
#include "Node.h"
class CChannel
{
public:
double *L, *h1, *h2; // h1 & h2 defined from the CL => make use of the problem assumed to be symmetric
std::vector<CNode> *GridPoints; // stores data for each individual grid point
CChannel(double, double, double);
~CChannel(void);
void MeshUniform(int); // creates a uniform distribution of nodes along the length of the channel
};
Channel.cpp
#include "Channel.h"
CChannel::CChannel(double length,double height1,double height2)
{
L=new double; // allocate memory
h1=new double;
h2=new double;
GridPoints = new std::vector<CNode>;
*L=length; // assign input values
*h1=height1;
*h2=height2;
}
CChannel::~CChannel(void)
{
delete L, h1, h2, GridPoints; // delete all the members of the class
}
void CChannel::MeshUniform(int NoNodes)
{
GridPoints->resize(NoNodes); // resize the vector
double dx=*L/(NoNodes-1); // increment of length between each pair of nodes
for (int i=0; i<NoNodes; i++)
*GridPoints->at(i).x=0.+i*dx; // assign the location to each node
}
As already described you do not need all these pointers - change them to be raw variable.
If you some day come to the situation where pointers are needed then remember of Rule of Three: What is The Rule of Three?.
You broke this rule by not defining copy constructor and assignment operator in your classes, like in this particular class:
class CNode
{
public:
double *alpha, *lambda; // properties dependent on the Pollhausen velocity profile
CNode(void);
~CNode(void);
void GetAlpha(void); // calculates alpha
};
You are using this CNode in std::vector<CNode> - so there you are suffering from wrong copying of this CNode object.
So you need to add copy constructor and assignment operator - then your problem should disappear even if you will be still using pointers, like in this simple example class:
class Example {
public:
Example() : p(new int()) {}
~Example() { delete p; }
Example(const Example& e) p(new int(e.p?*e.p:0)) {}
Example& operator = (Example e)
{
std::swap(e.p, p);
return *this;
}
private:
int* p;
};
It's compilcated but the explanation is that in your pointer code you haven't written objects that can be copied (as Piotr says you haven't followed the rule of three). Because of this bug what is happening is that memory is begin allocated, memory is being freed and then allocated again. By coincidence when you allocate memory again it reuses the same address that was just freed. That is why you see the same pointer values.
MyChan.GridPoints->at(0).alpha is a pointer but the memory it is pointing at has been freed. Then you allocate some more memory for Flow1.Uinf and it reuses the same freed memory that MyChan.GridPoints->at(0).alpha is pointing at. So you get the same value for both pointers.
One other misunderstanding you have
delete L, h1, h2, GridPoints; // delete all the members of the class
does not delete all members of the class. Only
delete L; // delete all the members of the class
delete h1;
delete h2;
delete GridPoints;
does that. What you wrote deletes GridPoints only. You might want to look up the C++ comma operator for an explanation as to why.
In C++, I'm having trouble with pointers etc. How can I fix the following problem?
error: no match for 'operator=' in '(stage->Stage::tiles + ((unsigned int)(((unsigned int)t) * 12u))) = (operator new(12u), (, ((Tile*))))'|
note: candidates are: Tile& Tile::operator=(const Tile&)|*
stage.h
#include "Tile.h"
class Stage {
public:
Tile *tiles;
int size;
void init(int size);
};
stage.cpp
void Stage::init(int size) {
this->size = size;
this->tiles = new Tile[size];
}
application.cpp
#include "Stage.h"
#include "Tile.h"
bool setTiles( Stage * stage ) {
for( int t = 0; t < stage->size; t++ ) {
stage->tiles[t] = new Tile();
}
return true;
}
stage.init(1234);
setTiles( &stage );
Also, I don't really know when to use object.attribute and when to use object->attribute?
stage->tiles[t] = new Tile();
You're calling new on something that's not a pointer. True, tiles is a pointer to an array, however, each element of that array is NOT a pointer. In order for that work, you would need an array of pointers, or a pointer to a pointer ,such as:
Tile **tiles;
What you could also do is create a separate pointer object, allocate it, and then copy the data to your array element by using
stage->tiles[i] = *somePointer;
and then deleting the pointer afterwards to free that allocated memory. This will preserve the copy because you invoked the copy constructor.
You are trying to allocate a pointer with a pointer to an array. Try this one:
class Stage {
public:
Tile **tiles;
void init(int size);
};
stage->tiles[t] = new Tile();
The above is not a valid C++ code, which you are perhaps confusing with the way new is used in other language such as C#. Though new can be used to allocate dynamic memories, but assigning an object to a particular element in the dynamically created array doesn't need the new construct. In fact, the object is already created as soon as you called new Tile[size]. What you may want to do is, create an object of type Tile and assign it to a particular element in tiles.
Tile myTile;
// do something with myTile
this->tiles[0] = myTile;
new Tiles() returns a pointer to a Tiles instance.
Tile *tiles defines an array out Tiles, not pointers.
Start with Tile **tiles instead.