I am making an array of 4 std::list. But when I try to access the array's first list's first A object and call the callMe() method on it I get a weird output.
Now 2 things could have happened:
Either the list was empty.
An A object was created when I tried to access the first element of the first list((*(arrayOflistOfA[0].begin()))).
Details of the above cases:
If no A object was created then I should have got an exception. But I didn't get any exception so I am assuming that an A object was created.
So if an A object was indeed created, then the constructor should have been called.
What am I missing?
#include <iostream>
using namespace std;
class A {
public:
A() {
cout<<"Constructor called"<<endl;
x=20;
}
void callMe();
private:
int x;
};
void A::callMe() {
cout<<"Value of x = "<<x<<endl;
}
int main() {
const int size = 4;
list<A>* arrayOflistOfA = new list<A>[size];
(*(arrayOflistOfA[0].begin())).callMe();
}
The output is:
Value of x = 0
but the output should have been:
Constructor called
Value of x = 20
If no A object was created then I should have got an exception.
Not true.
But I didn't get any exception so I am assuming that an A object was created.
Don't assume. Find out. Go to some documentation for begin() and for iterators and discover that you do not get an exception, you get UB.
An A object was created when I tried to access the first element of the first list((*(arrayOflistOfA[0].begin()))). [And] if an A object was indeed created, then the constructor should have been called.
That's right. Clearly you have no elements in the list.
And we know that, because there is no code in your program that adds elements to the list.
Also you should not dynamically allocate containers unless you really, really need to (I've never found a need to).
You aren't actually populating the list with any values. I tested the below code and include a commented explanation.
#include <iostream>
#include <list>
using namespace std;
class A {
public:
A();
void callMe();
private:
int x = 0;
};
A::A()
{
cout << "Constructor called" << endl;
x = 20;
}
void A::callMe() {
cout << "Value of x = " << x << endl;
}
int main() {
const int size = 4;
list<A>* arrayOflistOfA = new list<A>[size];
cout << arrayOflistOfA->size() << endl; // As you can see, size is 0 here - you created a list of nulls.
for (int i = 0; i < size; i++)
{
arrayOflistOfA->push_back(A());
}
// The below code demonstrates how to loop through the array once it's populated.
list<A>::iterator it;
for (auto& a : *arrayOflistOfA)
{
a.callMe();
}
return 0;
}
I got the answer to my question. Firstly I tried to run this code on my mac with GNU C++ compiler but when I ran the same code on an iPhone simulator it crashed. So as #PaulMcKenzie mentioned, I was indeed trying to dereference an invalid iterator.
Related
class test
{
int a;
static int cnt;
public:
test()
{
a=0;
cout <<++cnt;
}
test( int p)
{
a=p;
cout <<++cnt;
}
~test()
{
cout<<cnt--;
}
};
int test::cnt;
void main()
{
test ob,ob1(10);
ob = test();
test();
}
In this code snippet ob=test(); how ob can be assigned a function test.Test is a class and we are invoking it like a function.How can this be possible
Functions return void, objects, references or pointers to objects, that can generally be assigned to variables in your program. In this particular case, you are calling the test class object constructors and possibly encountering undefined behavior on the final call. I need to investigate further on the possible UB, the C++ standard has changed twice since I last read it, VS-2017 may not be the best oracle, and my C++ foo is little weak.
As far as I recall, there's more than one way to initialize an object in C++ and your instructor has obviously given you an assignment to learn this first hand.
test ob; // Invokes default constructor on test
test ob(); // Invokes default constructor on test.
test ob = test::test(); // Invokes default constructor on test.
It's always good to experiment with your code and get it to output usable diagnostics. I tweaked it a bit to get more organized output and force the app to wait on user input prior to exiting. You should also learn to use your debugger. You can learn a lot by simply stepping through your own code.
#include <iostream>
#include <cstdlib>
class test
{
int a;
static int cnt;
public:
test()
{
a = 0;
cnt++;
std::cout << cnt << std::endl;
}
test(int p)
{
a = p;
cnt++;
std::cout << cnt << std::endl;
}
~test()
{
std::cout << cnt << std::endl;
cnt--;
}
};
int test::cnt = 0;
int main(void)
{
{
test ob; // test::cnt is incremented, 1 is displayed on the console.
test ob1(10); // test::cnt is incremented, 2 is displayed on the console.
ob = test::test(); // test::cnt is incremented, 3 is displayed on the console.
// The following instantiates a temporary test object,
// the constructor is called, but test::cnt is not incremented on my system.
// Seems we might be in undefined behavior territory?
test::test();
}
system("pause");
}
Notice that I added an additional context to 'main()'. You can't rely on destructors outputting anything to the console after the end of 'main()' which is where your objects are destructed. Moving all the objects into the additional {} context, forces them to be constructed and destroyed therein, allowing us to a complete picture of what's going on at our console output.
The output on my Windows box for the above code is:
1
2
3
3
3
3
2
1
Press any key to continue . . .
I expected a count to 4 and then a count down from 4. That last call is definitely confusing me. If nobody chimes in with a definitive explanation, I'll look into it as soon as I can.
I have a task to create an object Stos which would feature a heap of objects Obiekt, to which I could add things as I please.
In order to make the program better support dynamic arrays I decided to use a Vector.
The whole implementation seems to run perfectly, the returned value is completely off.
Here is an example with code:
class Obiekt {
private:
int id;
public:
Obiekt::Obiekt(int i) {
id = i;
}
void Obiekt::display() {
cout << "This object has id of: " << id << endl;
}
};
class Stos {
private:
vector < Obiekt* > stos;
public:
Stos::Stos(Obiekt n) {
add(n);
}
void Stos::add(Obiekt n) {
stos.push_back(&n);
}
void Stos::display() {
cout << endl << "===HEAP DISPLAY===" << endl;
for (int i = 0; i < stos.size(); i++) {
stos[i]->display();
}
}
};
void Zad1()
{
Obiekt obj1(5);
Obiekt obj2(23);
Stos s1(obj1);
s1.add(obj2);
s1.display();
getchar();
}
And the outcome being:
===HEAP DISPLAY===
This object has id of: -858993460
This object has id of:9805925
I'm not a cpp expert, and believe the issue is related to the stos.push_back(&n) portion, but I can't catch the moment the id gets so distorted.
It's probably a noob question, so sorry for that on start.
Any help would be amazing.
The issue with your code as O'Neil correctly explained is that you're adding the pointer to a copy of the Obiekt object. So basically, you create your object in main, and pass it to the constructor and the .add function in Stos. You then add the pointer to the vector. When the function finishes, the copy that was passed is destroyed and the pointer in your vector is dangling.
There are two ways to fix this:
1 Pass by reference
This is very simple, basically you just add an ampersand to your function parameters. For instance:
void Stos::add(Obiekt &n) {
stos.push_back(&n);
}
This will ensure that the object isn't destroyed at the end of the function
2 Don't use pointers
Another way of getting your problem to work is to avoid using pointers at all. Your vector will actually copy the contents of the Obiekt object into it. For example:
vector < Obiekt > stos; // notice how we define it without the pointer type
...
void Stos::add(Obiekt n) {
stos.push_back(n); // Creates copy which will then contain the correct value
}
The parameters Obiekt n in
Stos::Stos(Obiekt n) {
add(n);
}
void Stos::add(Obiekt n) {
stos.push_back(&n);
}
are temporary copies destroyed immediatly after each call.
You have to use a reference Obiekt & n instead, or better: by pointer Obiekt * n.
I'm reluctant to assert that the objects exist at the time display is called.
Problem(s)
According to GCC's implementation they don't.
They fall out of scope and are immediately destructed. Give "Obiekt" a non-trivial destructor and this behavior becomes obvious:
~Obiekt(){std::cout << "Bye from: " << it << std::endl;}
Secondarily, note that you shouldn't specify the class membership for functions defined within the class itself (no class_name::function_name(parameters), just function_name(parameters) )
Possible Fix
You (might) want to changing "Stos" such that:
Stos(Obiekt &n) {add(n);}
void add(Obiekt &n) {stos.push_back(&n);}
I have two sample classes Sample and Hello
The Hello has a map which contains a map in heap, that map has Class Sample's object in it's value type.
class Hello
{
public:
map<int,Sample>* samMap;
};
And my function has a code like this
Hello * h = new Hello;
{
h->samMap = new map<int,Sample>;
for(int i=0 ; i<100000;i++)
{
Sample se;
se.a = i*2;
se.b = i*5;
se.vecInt = new vector<int>;
se.vecInt->push_back(i+2);
h->samMap->insert(make_pair(i,se));
}
}
map<int,Sample>::iterator ss = h->samMap->find(50);
if(ss != h->samMap->end())
{
cout << " Value : " << ss->second.a << " " << ss->second.b << endl;
for(int s=0; s<ss->second.vecInt->size(); s++)
{
cout << ss->second.vecInt->at(s) << endl;
}
}
From the above code, the Sample object is declared and used inside a block. Once the control comes out of block the stack object have to get cleared.
But still i can iterate the map and get the Sample's objects outside the for loop without any access violation exception.How is that possible? While inserting the object to container a new copy of object is inserted ?
Yes. Because you're not storing a pointer or reference, a copy is made when you add it to the map.
Of course, if class Sample has a destructor to delete vecInt, it will also need a copy constructor; otherwise the pointer in the map's copy becomes invalid when the local "original" goes out of scope.
The correct way here is to avoid deep copies and use memory management support from the standard library: most usages of new are a sign of poor design. For example (I'm guessing a bit about the guts of Sample)
class Sample
{
int a=0, b=0;
std::vector<int> vecint; // not a pointer, but data member
public:
Sample(int _a, int _b) // construct sample with empty vecint
: a(_a), b(_b) {}
void add(int x) // add to vecint
{ vecint.push_back(x); }
};
struct Hello
{
std::map<int,Sample> samMap;
};
Hello makeHello()
{
Hello hello;
for(int i=0; i<100000; ++i)
{
auto r = hello.samMap.emplace(std::piecewise_construct,
std::forward_as_tuple(i),
std::forward_as_tuple(i*2,i*5));
if(!r.second)
throw std::runtime_error("couldn't insert new Sample for key '"+std::to_string(i)+"'");
r.first->second.add(i+2); // add to inserted Sample
}
return hello;
}
Note: no call to new and, consequently, no call to delete. It's all done under the hood by the standard library containers std::map and std::vector.
See also the documentation for std::map and std::map::emplace.
Both sections of code below are drastically simplified, isolated versions of my actual code. The examples are just big enough to reproduce the problem. The first section of code below works fine. The section section is an attempt to begin to make it part of a class. I'm trying to take tiny steps since small modifications to something like the struct shown below require lots of changes throughout the code which is full of pointers, pointer to pointers and references which all involve this struct. Can you tell me why the second section of code throws a stack overflow within it's constructor and what small changes can be made to fix it?
Working code:
#include <cstdio>
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
const int maxSize = 3;
struct Item{
int count;
Item *items[maxSize + 1];
};
void foo()
{
Item *p;
p = new Item();
p->count = 2;
cout << p->count << endl;
}
int main(int argc, char *argv[])
{
foo();
return 0;
}
Attempt to very gradually modify the code as a whole toward becoming a class:
#include <cstdio>
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
int maxSize = 3;
struct Item{
int count;
Item *items;
Item()
{
items = new Item[maxSize + 1]; // stack overflow
}
};
void Initialize(int size)
{
maxSize = size;
}
void foo()
{
Item *p;
p = new Item();
p->count = 2;
cout << p->count << endl;
}
int main(int argc, char *argv[])
{
Initialize(5);
foo();
return 0;
}
The first call to construct a Item calls new Item[maxSize+1], which calls the default constructor, which calls new Item[maxSize+1], which calls the default construct, and so on until you reach stack overflow.
All the answers are right. I want to suggest a solution for you:
Instead of initializing the array within the ctor, you could implement an initialization method like
init(int maxSize) {
items = new Item[maxSize + 1];
}
that you can call after having constructed the object. This should avoid the stack overflow. In general, you should avoid to place instances of an object inside the object itself. Its better to use Collections of the Item
List<Item>, std::vector<Item>, ...
It is because in working version you have reference to an array of object, but not actual object of Items. In second version, you are creating objects by using keyword new. So, in second version in constructor it will call itself! It will call it's own constructor infinite times. Hence, you see runtime exception stackoverflow :)
Above posters are right. Within the constructor of Item you create items (by creating an array). So the ctor is again called, which creates more items, which .... This is more or less an infinite loop which eats up your stack.
Either stick with the references or use a collection like List - so you can add the items later on dynamically.
I have a problem when copying pointers to objects that contain tables... Some information is kept (strings, for example skillName), but the tables contain new, random data. I tried several things, but I still don't know what's wrong and how to do it... Help me, please. :)
EDIT: I've edited whole post, and as WhozCraig suggested made it MCVE (at least I tried).
Everything now is in this block of code, so you can just copy it and see it for yourself. For some reason the problem is in different location now, but it's still the same...
#include <iostream>
#include <string>
using namespace std;
class Skill
{
protected:
int const maxSkillLevel;
short skillLevel;
string skillName;
public:
Skill(string skillName) : maxSkillLevel(5){
skillLevel = 0;
this->skillName = skillName;
}
virtual ~Skill(){}
virtual int getMaxDmg(int i){ return 0; };
void increaseSkillLevel(int);
string getSkillName(){ return skillName; }
};
class OffensiveSkill : public Skill{
protected:
int *maxDmg;
public:
OffensiveSkill(string skillName, int maxDmg[]) : Skill(skillName){
this->maxDmg = maxDmg;
}
~OffensiveSkill(){}
int getMaxDmg(int i){ return maxDmg[i]; }
};
class Role{
protected:
string roleName;
Skill **skills;
public:
Role(string roleName){
skills = new Skill*[3];
this->roleName = roleName;
}
Role(Role* role){
this->skills = role->getSkills();
this->roleName = role->getRoleName();
}
Skill **getSkills(){ return skills; }
string getRoleName(){ return roleName; }
void setSkills(Skill* s1){ skills[0] = s1; }
};
class RoleGenerator{
protected:
Role *role;
public:
RoleGenerator(){
role = new Role("assassin");
int maxDmg[5] = { 30, 45, 60, 75, 90 };
OffensiveSkill* assassinate = new OffensiveSkill("Assassinate", maxDmg);
role->setSkills(assassinate);
cout << "maxDmg in RoleGenerator " << role->getSkills()[0]->getMaxDmg(0) << endl;
}
Role *getRoles(){ return role; }
};
int main(){
RoleGenerator* rg = new RoleGenerator();
Role *role = rg->getRoles();
cout << "maxDmg in main " << role->getSkills()[0]->getMaxDmg(0) << endl;
Role *copied = new Role(role);
//maxDmg here is different
cout << "maxDmg in after copying " << role->getSkills()[0]->getMaxDmg(0) << endl;
//but skill name is copied correctly
cout << "skill name " << role->getSkills()[0]->getSkillName() << endl;
}
The local array in RoleGenerator:: RoleGenerator()
int maxDmg[5] = { 30, 45, 60, 75, 90 };
is being passed as-address to:
OffensiveSkill* assassinate = new OffensiveSkill("Assassinate", maxDmg);
where that address is saved via:
this->maxDmg = maxDmg;
After RoleGenerator:: RoleGenerator() returns maxDmg is no longer valid to address. Dereferencing the saved address later invokes undefined behavior.
If a copy is sufficient one way to make this trivial is by copying the array into a simple member array or vector. There are multiple ways to do this. A decent arbitrary-length solution using a vector would be something like this:
#include <vector>
class OffensiveSkill : public Skill {
protected:
std::vector<int> maxDmg;
public:
template<size_t N>
OffensiveSkill(string skillName, int (&dmg)[N])
: Skill(skillName)
, maxDmg(dmg, dmg+N)
{
}
int getMaxDmg(int i) const { return maxDmg[i]; }
};
That alone should work as a drop-in replacement for your exiting constructor and class definition. If needed you can offer up additional flexibility by providing alternate constructors, such as one that allows beginning and end iterators directly passable to maxDmg construction, an int* and size_t length, etc.
And I would suggest you modify your indexing member getMaxDmg() to (a) range check the input value and toss an exception if out of range, and (b) use an unsigned data type (such as std::size_t) for your indexes. Unrelated to your question, but worth considering.
This is looking strange:
skills[0] = static_cast<OffensiveSkill*>(roleSkills[0]);
You would need to include more of your code.
But, based on the limited information, looks like you are better off with a copy constructor that is custom. A compiler generated copy-constructor won't perform deep-copy for you.