Accessing specific objects using pointer to multiple arrays of pointers - c++

EDIT: Pasting portion of code that is giving me this issue. Although in my effort to cleanup some of the comments before pasting it here I ended up with a different error. Still happens in the same place though: "munmap_chunk(): invalid pointer
Aborted (core dumped)".
Learning C++; working on polymorphism.
I created a virtual base class and the idea is to have multiple child classes, although I'm currently just stuck on one. My program cannot use vectors, and must include a lambda, so I thought one way to incorporate it would be to just have a function that loops through all my objects and sends the object to the lambda which simply displays the name.
My issue is that I'm trying to figure out how to write the function and lambda parameters/arguments so that it accepts and can work with all my objects. I thought using the base class to create an array of pointers would e the answer but it's resulting in a segmentation fault.
Perhaps I'm misunderstanding inheritance, or perhaps unclear about the way I should be using the pointers and looping through the arrays?
#include <iostream>
#include <string>
#include <cstdlib>
#include <iomanip>
using namespace std;
//Hokeemon Class parent to Child class(es)
class Hokeemon {
friend ostream &operator<< (ostream &stream, Hokeemon &critter);
public:
// int hat, eyes, mouth, health = 0, boredom = 0; string name;//bool alive;
string name;
// virtual string changeName(string); // offers user to change critter name
// virtual void passTime(){health--; boredom++;};
// virtual void description(){};
virtual string getName(){return name;};
};
class Playful : public Hokeemon{ //inherits from parent Hokeemon
public:
Playful() {
cout << "Hokeemon's being hatched.\n";
name = "Test";
}
~Playful(){cout << "Hookemon deleted" << endl;};
};
void forEach(int objects, Hokeemon** ptr, int**, void(*func)(Hokeemon &critter));
int main() {
int obj = 1, aliveSize = 3; int playSize;
srand((time(NULL)));// seed for random numbers
playSize = aliveSize;
int* arraySizes[obj]{}; //to hold sizes of child class arrays
Hokeemon* hPtr[obj];
hPtr[0] = new Playful[playSize]; arraySizes[0] = &playSize; //creates pointer to array of pointers for objects of class Playful
forEach(obj, hPtr, arraySizes, [](Hokeemon &critter){ cout << critter.getName();}); //<< endl; critter.description();});
delete hPtr[0];
return 0;
}
void forEach(int obj, Hokeemon **hArray, int** array, void(*func)(Hokeemon &critter)){
Hokeemon* temp = NULL; //create pointer to hold pointers in array
for( int i = 0; i < obj; i++){ //this level loops through objects in array
temp = hArray[i]; //assigns temp pointer to applicable class pointer
for (int j = 0; j < *array[i]; j++){// loops through objects in class
func(temp[j]);
}
}
}
I can't get it to print past the first object (ptr[0][0] if I'm understanding correctly). I've tried manually printing ptr[0][1] and I get a segmentation fault. How should I be doing it so that I can access the second object of the Child class? Again, I'd like to keep it general so that I can easily add in another Child class and just change the array slightly.

Related

Difficulty understanding c++ polymorphism

What I am trying to achieve is creating a superclass array of subclass objects.
In this particular test I'm working on, I want to have an animal array that has some dog objs and some cat objs while they maintain their attributes.
#include <iostream>
using namespace std;
//ANIMAL
class animal
{
protected:
int ID;
string name;
public:
animal(string = "Unknown");
int get_ID() { return ID; }
virtual string get_name() { return name; }
};
animal::animal(string n) { name = n; }
//DOG
class dog : public animal
{
static int newID;
string sound;
public:
dog(string = "Corgi", string = "Woof!");
string get_name() { return sound + " " + name; }
};
int dog::newID = 0;
dog::dog(string n, string s) : animal(n)
{
newID++;
ID = newID;
cout << ID << "\t";
sound = s;
}
//CAT
class cat : public animal
{
static int meowID;
string color;
public:
cat(string = "Munchkin", string = "Calico");
string get_name() { return color + " " + name; }
};
int cat::meowID = 89;
cat::cat(string n, string c) : animal(n)
{
meowID++;
ID = meowID;
cout << ID << "\t";
color = c;
}
//MAIN
int main(int argc, char* argv[])
{
animal** test;
animal* p;
for (int i = 0; i < 6; i++)
{
p = new dog;
p++;
}
cout << "\n";
for (int i = 0; i < 6; i++)
{
p = new cat;
p++;
}
cout << "\n";
test = &p;
cout << (*test-7)->get_ID();
return 0;
}
What I've learned so far is that p isn't an array, and it keeps pointing to different memory addresses through the loops.
I cannot do animal** test = new dog[6]; as it is an invalid initialization. Even if that worked I would have trouble cascading another array segment of cat.
This is the output I obtained:
1 2 3 4 5 6
90 91 92 93 94 95
0
The first line is displaying dog IDs being invoked 6 times, and the second line is displaying cat IDs being invoked 6 times. (*test-7)->get_ID();is the last number.
It seems the constructors are being invoked right. However, I have no idea where my pointer is pointing, since I am expecting 91 not 0.
How do I get an animal array that I can access information from each element? For example,
animal** myArray;
{do something}
cout << myArray[2].get_name() << endl << myArray[7].get_ID();
and it outputs
Woof! Corgi
91
One important detail about the animal class: polymorphic types can run into issues when their destructors are called but those destructors are not virtual. It is recommended that you make the destructor of the base class virtual, even if that class itself does not actually need a destructor. In this case, you can tell the compiler that you want the destructor to be virtual but generate a default implementation of it with:
virtual ~animal() = default;
Add the above line in the public: section of your animal class. This ensures that any derived classes that you define later on will get a virtual destructor automatically.
Now to the rest of your code:
p = new dog;
So far, so good. But then this:
p++;
does nothing useful other than making the pointer point to an invalid address. Then in the next iteration, another p = new dog; will be performed. The previous dog object you allocated is now lost forever. You got a so-called "leak".
It seems you expect new to allocate objects an a way that lays them out in memory one after another. That is not the case. new will allocate memory in an unpredictable location. As a result, this:
*test-7
cannot possibly work, as the objects are not laid out in memory the way you expected. What you get instead is an address to some memory location 7 "positions" before the latest allocated object that pretty much certainly does not point to the animal object you were hoping. And when you later dereference that you get undefined behavior. Once that happens, you cannot reason about the results anymore. They can be anything, from seeing wrong text being printed to your program crashing.
If you want an array of animal pointers, you should specifically create one:
animal* animals[12];
This creates an array named animals that contains 12 animal pointers. You can then initialize those pointers:
for (int i = 0; i < 6; i++) {
animals[i] = new dog;
}
cout << "\n";
for (int i = 6; i < 12; i++) {
animals[i] = new cat;
}
You then just specify the array index of the one you want to access:
cout << animals[0]->get_ID() << '\n'; // first animal
cout << animals[6]->get_ID() << '\n'; // seventh animal
Don't forget to delete the objects after you're done with the array. Since animals is an array, you can use a ranged for loop to delete all objects in it:
for (auto* animal_obj : animals) {
delete animal_obj;
}
However, all this low-level code is quite tedious and error-prone. It's recommended to instead use library facilities that do the allocations and cleanup for you, like std::unique_ptr in this case. As a first step, you can replace your raw animal* pointer with an std::unique_ptr<animal>:
unique_ptr<animal> animals[12];
(Don't forget to #include <memory> in your source file, since std::unique_ptr is provided by that library header.)
Now you've got an array of smart pointers instead of raw pointers. You can initialize that array with:
for (int i = 0; i < 6; i++) {
animals[i] = make_unique<dog>();
}
cout << "\n";
for (int i = 6; i < 12; i++) {
animals[i] = make_unique<cat>();
}
Now you don't need to delete anything. The smart pointer will do that automatically for you once it goes out of scope (which in this case means once the animals array goes out of scope, which happens when your main() function exits.)
As a second step, you can replace the animals array with an std::vector or an std::array. Which one you choose depends on whether or not you want your array to be able to grow or shrink later on. If you only ever need exactly 12 objects in the array, then std::array will do:
array<unique_ptr<animal>, 12> animals;
(You need to #include <array>.)
Nothing else changes. The for loops stay the same.
std::array is a better choice than a plain array (also known as "built-in array") because it provides a .size() member function that tells you the amount of elements the array can hold. So you don't have to keep track of the number 12 manually. Also, an std::array will not decay to a pointer, like a plain array will do, when you pass it to functions that take an animal* as a parameter. This prevents some common coding bugs. If you wanted to actually get an animal* pointer from an std::array, you can use its .data() member function, which returns a pointer to the first element of the array.
If you want the array to be able to grow or shrink at runtime, rather than have a fixed size that is set at compile time, then you can use an std::vector instead:
vector<unique_ptr<animal>> animals;
(You need to #include <vector>.)
This creates an empty vector that can store elements of type unique_ptr<animal>. To actually add elements to it, you use the .push_back() function of std::vector:
// Add 6 dogs.
for (int i = 0; i < 6; i++) {
animals.push_back(make_unique<dog>());
}
// Add 6 cats.
for (int i = 0; i < 6; i++) {
animals.push_back(make_unique<cat>());
}
Instead of push_back() you can use emplace_back() as an optimization, but in this case it doesn't matter much. They key point to keep in mind here is that a vector will automatically grow once you push elements into it. It will do this automatically without you having to manually allocate new elements. This makes writing code easier and less error-prone.
Once the vector goes out of scope (here, when main() returns,) the vector will automatically delete the memory it has allocated to store the elements, and since those elements are smart pointers, they in turn will automatically delete the animal objects they point to.
If you're new to C++, it's important that you get started on the right foot and to follow modern best practices, namely:
Avoid using pointers, new, delete, new[] and delete[].
Instead use smart-pointers (unique_ptr, shared_ptr, but don't use auto_ptr!).
Use the make_ functions instead of new. That way you don't need to worry about delete.
See Advantages of using std::make_unique over new operator
Use std::vector<T> (and std::array<T,N> if you have fixed-size collections) instead of new[] or p** (and never use malloc or calloc directly in C++!)
I note that you should also generally prefer Composition over Inheritance, but with trivial examples like yours it's difficult to demonstrate the concept because a Dog and a Cat "are" Animals.
I also note that when the possible set of subclasses is known at compile-time you should consider using a union-type instead of subclassing because it allows consumers to exhaustively work with returned values without needing to use RTTI or guesswork.
This can be done with using AnAnimal = std::variant<cat,dog>.
Anyway, this is what I came-up with. The class animal, class dog, and class cat code is identical to your posted code (and is located within the // #region comments), but the #include and using statements at the top are different, as is the main method.
Note that my code assumes you have a compiler that complies to the C++14 language spec and STL. Your compiler may default to C++11 or older. The std::make_unique and std::move functions require C++14.
Like so:
#include <iostream>
#include <memory>
#include <vector>
#include <string>
// Containers:
using std::vector;
using std::string;
// Smart pointers:
using std::unique_ptr;
using std::move;
using std::make_unique;
// IO:
using std::cout;
using std::endl;
// #region Original classes
//ANIMAL
class animal
{
protected:
int ID;
string name;
public:
animal(string = "Unknown");
int get_ID() { return ID; }
virtual string get_name() { return name; }
};
animal::animal(string n) { name = n; }
//DOG
class dog : public animal
{
static int newID;
string sound;
public:
dog(string = "Corgi", string = "Woof!");
string get_name() { return sound + " " + name; }
};
int dog::newID = 0;
dog::dog(string n, string s) : animal(n)
{
newID++;
ID = newID;
cout << ID << "\t";
sound = s;
}
//CAT
class cat : public animal
{
static int meowID;
string color;
public:
cat(string = "Munchkin", string = "Calico");
string get_name() { return color + " " + name; }
};
int cat::meowID = 89;
cat::cat(string n, string c) : animal(n)
{
meowID++;
ID = meowID;
cout << ID << "\t";
color = c;
}
// #endregion
int main()
{
// See https://stackoverflow.com/questions/44434706/unique-pointer-to-vector-and-polymorphism
vector<unique_ptr<animal>> menagerie;
// Add 6 dogs:
for( int i = 0; i < 6; i++ ) {
menagerie.emplace_back( make_unique<dog>() );
}
// Add 6 cats:
for( int i = 0; i < 6; i++ ) {
menagerie.emplace_back( make_unique<cat>() );
}
// Dump:
for ( auto &animal : menagerie ) {
cout << "Id: " << animal->get_ID() << ", Name: \"" << animal->get_name() << "\"" << endl;
}
return 0;
}

How to access variables in a class using an array of objects?

I am new to pointers and I am having trouble in accessing the variables inside a class.
I want to make a sort of database of possible moves in a Chess game, and I think that using pointers is the way to go, since I wouldn't be wasting memory and prevent any unnecessary memory errors.
main.cpp
#include <iostream>
#include "moves.h"
using namespace std;
int main()
{
moves* possibleMoves[100];
&(possibleMoves[0]->piece) = 100;
cout << *&possibleMoves[0]->piece << endl;
return 0;
}
moves.h
#ifndef MOVES_H
#define MOVES_H
class moves
{
public:
moves();
int piece;
int X;
int Y;
int addX;
int addY;
int score;
};
#endif // MOVES_H
Any help would be appreciated. Thank you very much in advance.
Currently it doesn't output anything and I don't know what to do.
I am having trouble in accessing the variables inside a class
It looks like you are making a mess of pointers and references.
There isn't a real need in your code to use array of pointers. Instead using normal array of objects would do.
moves possibleMoves[100];
possibleMoves[0].piece = 100;
cout << possibleMoves[0].piece << endl;
Btw, class moves incorrectly exposes all data members to public - they should be private. And moves constructor needs to be implemented or otherwise should be removed to use the default one.
You are creating an array of pointers with:
moves* possibleMoves[100];
when what you want is an array of moves.
Then you are trying to assign piece in possibleMoves[0] a value of 100 with:
&(possibleMoves[0]->piece) = 100;
but you are actually doing something quite different. As #Henri Menke said best to read up on &, *, . and ->.
To make your intended code work try:
int main()
{
moves possibleMoves[100];
possibleMoves[0].piece = 100;
cout << possibleMoves[0].piece << endl;
return 0;
}
Here you create an array of moves objects, then assign the value of piece in object 0 a value of 100. You retrieve the value and print it to cout.

C++ Dynamic Array Member Variable Assignment

I am having a problem with assigning new values to a dynamic int array that is a data member variable of the class IntersectionFlowRate(). I can initialize and print the values of the array inside the constructor. However, when I exit the constructor to the another class and then later call a function within the IntersectionFlowRate() class passing in variables to overwrite the initial values of the data member it will segmentation fault. I have debugged to find that overwriting the array is causing the seg fault. And that even attempting to access the dynamic array within one of its functions will seg fault.
My question is how can I edit the values of a dynamic int array member variable from within one of its functions i.e setArrayElement(int index, int x).
Here is some of my code. Sorry if I am unclear or missing something ridiculous. I have been stuck on this for hours.
#ifndef INTERSECTIONFLOWRATE_H
#define INTERSECTIONFLOWRATE_H
class IntersectionFlowRate
{
public:
IntersectionFlowRate();
~IntersectionFlowRate();
void setFlowCycle(int index, int flow);
private:
int* m_flowRateMotorCycle;
};
#endif
in the .h file ^
#include "IntersectionFlowRate.h"
#include <cstdlib>
#include <iostream>
#include <new>
using namespace std;
IntersectionFlowRate::IntersectionFlowRate()
{
const int SIZE = 4; //Constant for m_flowRates[] size
//DYNAMIC MEMORY DELETE LATER
m_flowRateMotorCycle = new int[SIZE];
for(int i = 0; i < SIZE; i++){
m_flowRateMotorCycle[i] = 0;
cout << m_flowRateMotorCycle[i] << endl;
cout << "WE GOT HERE" << endl;
}
}
void IntersectionFlowRate::setFlowCycle(int index, int flow){
cout << "INDEX: " << index << endl;
cout << "FLOW: " << flow << endl;
m_flowRateMotorCycle[index] = flow; //seg fault is here
}
I have another class that creates a pointer to a IntersectionFlowRate() object and then calls its setFlowCycle function passing in two VALID ints. With the debugging I was able pass 0 and 3 to the function setFlowCycle(0, 3) just fine and output those variables within the function.
#ifndef TRAFFICSIM_H
#define TRAFFICSIM_H
#include "IntersectionFlowRate.h"
using namespace std;
class TrafficSim
{
public:
TrafficSim(); //Default Constructor
TrafficSim(const char* file); //Constructor
~TrafficSim(); //Destructor
private:
IntersectionFlowRate* m_flowRate;
};
#endif
#include "TrafficSim.h"
#include "IntersectionFlowRate.h"
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
TrafficSim::TrafficSim()
{
IntersectionFlowRate* m_flowRate = new IntersectionFlowRate();
m_flowRate->setFlowCycle(0, 3);
}
I replicated the error with this code. If no one else can I am completely unsure of what is possibly wrong anymore.
You are setting a local variable called m_flowRate, not the member variable m_flowRate of your TrafficSim class:
Instead of this:
TrafficSim::TrafficSim()
{
IntersectionFlowRate* m_flowRate = new IntersectionFlowRate();
m_flowRate->setFlowCycle(0, 3);
}
It should be this:
TrafficSim::TrafficSim()
{
m_flowRate = new IntersectionFlowRate();
m_flowRate->setFlowCycle(0, 3);
}
But overall, it not need be a pointer. It could be an object member within your class. That would cut down on the pointer usage a bit:
class TrafficSim
{
public:
TrafficSim(); //Default Constructor
TrafficSim(const char* file); //Constructor
private:
IntersectionFlowRate m_flowRate;
};
Then:
TrafficSim::TrafficSim()
{
m_flowRate.setFlowCycle(0, 3);
}
As to your question as to how to incorporate usage of std::vector in your class, here is a code sample of the IntersectionFlowRate class, rewritten using vector:
Vector sample
Also, another source of problems is that your classes fail to follow the Rule of 3 when you have pointers to dynamically allocated memory in your class.
Using std::vector takes care of this automatically, but if you insist on using pointers, you need to adhere to the directions at the link posted.
Yes, use a std::vector, it is much simpler, and it is a template so it also pretty fast and works any type (best for primitive types or pointers to objects) , and it also has boundary checking and other useful things.
If you need fast array-like access then you could use std::map which associates a key with a value, like so
std::map<UINT, YourClass*> m_mapIDs_to_YourClass;
When you first start using stl containers they might seem a little strange, but after a short while you cannot do without them, luckily they have been part of the C++ standard for some time now.
Boundary check for both these containers can be done by comparing your iterator to mapYourMap.end(), if they are equal you have passed the last element and trying to access data through the iterator will cause an exception.
Example for std::vector (if vecInt is a vector< int >):
vector<int>::iterator it = vecInt.begind();
if (it == vecInt.end()) return; // vector is empty
do { // runs through elememts until out of bound, useful for searching
i++
while (it != vecInt.end());

How do I point at a vector in another class?

I have a class that holds a vector, which also inherits another class:
class txtExt : public extention
{
private:
string openedFile_;
public:
vector<string> txtVector; //the vector i want to call
};
I fill the vector in a method within a class:
class Manager : public extention
{
// there is some other code here that I know does work
// and it calls this function:
void organizeExtention(string filename, string ext)
{
if(ext == "txt")
{
txtExt txtExt;
txtExt.txtVector.pushback(filename);
}
}
}
and this is my main class where i attempt to call the vector:
int main()
{
// some code here that does previous operations like getting the path
// and filling the vector
// I've tried many ways of trying to call the vector
// here is an example of one:
vector<txtExt*> testVector;
for(int i = 0; i < testVector.size(); ++i)
{
cout << testVector[i] << endl;
}
return 0;
}
I have a few questions:
Am I calling the vector wrong?
Is my vector empty?
Do I have to make my vector global, so other classes can see it?
Note: I've been able to print out the vector where I load the vector using a very simple for loop
Well, as has been said you have a few errors in the code posted, and you maybe have some misunderstandings as well. But to answer the question asked, this
testVector[i]->txtVector
is the way to access the txtVector object that is inside each of your txtExt objects.
If that doesn't work for you then it's because one of the other errors/misunderstandings you have in your code.
To summarize:
reread the first chapters of a good C++ book ( The Definitive C++ Book Guide and List ), then try try to fix your program and deal with each error one at the time.
There are several errors in your code.
First of all, there's no operator << for printing entities of the type txtExt*.
Even object of type txtExt is not printable just like that.
In addition, the testVector you made is empty, so no .size() will be zero, and there's going to be no looping.
Are you really sure that you like to inherit both your classes from 'extension' ?
You can't call a vector, you can access it.
Having a data member (like the vector) public is not a good idea.
Calling a variable by the same name as a class is a very bad idea.
I have trouble guessing what your code should do. Here's a simple example of things you need to understand:
#include <iostream>
#include <vector>
#include <string>
class TxtExt
{
public:
std::vector<std::string> txtVector;
};
int main(){
TxtExt oneTxtExt;
oneTxtExt.txtVector.push_back("hello");
oneTxtExt.txtVector.push_back("world");
for( auto &i : oneTxtExt.txtVector ){
std::cout << i <<std::endl;
}
}
The following code is correct, but has absolutely no effect. You could as well just write {}:
{
TxtExt TxtExt;
TxtExt.txtVector.pushback(filename);
}
You here create a new object, push back to it (btw it is called push_back), but then the object is destroyed at the end of the scope. Also, don't name you objects the same as the class, it becomes really confusing.

Need help with map (c++, STL)

Actually I'm new to C++. I tried something out (actually the map container) but it doesn't work the way I assumed it will... Before posting my code, I will explain it shortly.
I created 3 classes:
ClassA
ClassDerivedA
ClassAnotherDerivedA
The two last ones are derived from "ClassA".
Further I created a map:
map<string,ClassA> test_map;
I put some objects (from Type ClassDerivedA and ClassAnotherDerivedA) into the map. Keep in mind: the mapped value is from type "ClassA". This will only work because of Polymorphism. Finally I created an iterator which runs over my map and compares the user input with my keys in the map. If they match, it will call a specific method called "printOutput".
And there is the Problem:
Although i declared "printOutput" as "virtual" the only method called is the one from my base class, but why?
and here is the code:
#include <iostream>
#include <map>
using namespace std;
class ClassA
{
public:
virtual void printOutput() { cout << "ClassA" << endl; }
};
class ClassDerivedA : public ClassA
{
public:
void printOutput() { cout << "ClassDerivedA" << endl; }
};
class ClassAnotherDerivedA: public ClassA
{
public:
void printOutput() { cout << "ClassAnotherDerivedA" << endl; }
};
int main()
{
ClassDerivedA class_derived_a;
ClassAnotherDerivedA class_another_a;
map<string,ClassA> test_map;
test_map.insert(pair<string,ClassA>("deriveda", class_derived_a));
test_map.insert(pair<string,ClassA>("anothera", class_another_a));
string s;
while( cin >> s )
{
if( s != "quit" )
{
map<string,ClassA>::iterator it = test_map.find(s);
if(it != test_map.end())
it->second.printOutput();
}
else
break;
}
}
The problem is slicing. You are storing ClassA values in your map. When you store derived class instances into the map, the get sliced into ClassA objects. You'll need to store pointers in your map instead of values.
See this for more info on slicing: What is object slicing?
C++ is not Java. You cannot store a derived type in a variable of a base type. For example:
Base b = Derived();
will only store the Base part of Derived in the variable b. In order to get polymorphic behaviour, you would need to use pointers, and create the derived class dynamically:
Base * b = new Derived();
The same goes for C++ containers - you need:
map <string, Base *> m;
All of this should be covered in every introductory C++ text book - which one are you using?
You are experiencing "slicing". To get the virtual functions to work properly, you need to call them using a pointer or a reference. In other words, your map should contain pointers to ClassA:
map<string, ClassA *> test_map
Please remember to delete them when you are done, or use smart pointers.
Here's more on slicing: here, here, and here