In the code below, why can I call printAlternativ but not print?
To my understanding, the object should be removed and neither should work.
using namespace std;
class MemTest
{
public:
MemTest(string);
~MemTest();
void print();
void printAlternative();
string name;
};
void MemTest::print() {
cout << "Print: " << name << "\n";
}
void MemTest::printAlternative() {
cout << "Print Alternative\n";
}
MemTest::MemTest(string n) {
cout << "Constructor\n";
name = n;
}
MemTest::~MemTest() {
cout << "Destructor\n";
}
void call(MemTest *b) {
MemTest a("TestName");
a.print();
b = &a;
}
int main()
{
MemTest *b = NULL;
call(b);
b->print(); // This crashes
// b->printAlternative(); This works
return 0;
}
After call() object get destructed, so now object b does not have any reference of any object and you are trying to access "name" data member of object because of that it get crashed.
You can verify it by adding a cout<<"Test line"; after call(b); line in main()
And why other one is working because member functions are associated with class and get assigned when first time we declare object and compiler only swipe data member in destructor()
Related
I'm new to the world of C++ (and OOP).
I'm learning about classes and pointers at this moment, but I'm stuck and hope someone can explain to me what I'm missing or should dig deeper into to broaden my understanding.
Example 1 works:
#include <iostream>
#include <string.h>
using namespace std;
class MyClass
{
private:
char* age;
public:
MyClass(const char* initData)
{
age = NULL;
cout << "In default constructor working on pointers" << endl;
age = new char [strlen(initData)+1];
strcpy(age,initData);
//age = initData;
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete [] age;
}
const char* GetAge()
{
return age;
}
};
int main()
{
//MyClass firstClass(10);
//cout << "First attempt: " ;
//cout << firstClass.GetAge() << endl;
MyClass secondClass("A test from B");
cout << "Second attempt: ";
cout << secondClass.GetAge() << endl;
return 0;
}
However This does not work:
#include <iostream>
#include <string.h>
using namespace std;
class MyClass
{
private:
int* age;
public:
MyClass(const int* initData)
{
cout << "In default constructor working on pointers" << endl;
age = new int;
//strcpy(age,initData);
age = initData;
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete age;
}
const int* GetAge()
{
return age;
}
};
int main()
{
MyClass firstClass(10);
cout << "First attempt: " ;
cout << firstClass.GetAge() << endl;
//MyClass secondClass("B");
//cout << "Second attempt: ";
//cout << secondClass.GetAge() << endl;
return 0;
}
I feel that it has to do with the fact that I pass an int to a constant pointer.
And then try to assign a constant from r-value to l-value with the = operator.
Although it think this is permitted, since I say 'const int* initData' and this tells the compiler to keep the data from changing but memory address can change?
So in my understanding, I pass value 10 to the class that makes a pointer in the default constructor, this makes a memory address and stores it in initData.
I then pass the r-value InitData (mem address) to the l-value age pointer, that accepts memory addresses.
If I try with the exact same code, but use char and copy data over in my first example it works...
Can anyone explain to me what I'm missing, Thanks in advance!
Edit:
I Think I found my solution and understand it better.
Could anyone verify that this is correct, or which is the (more) correct form:
Scenario 1:
#include <iostream>
using namespace std;
class MyClass
{
private:
int* age;
public:
MyClass(const int *initData)
{
cout << "In default constructor working on pointers" << endl;
age = new int;
(*age) = (*initData);
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete age;
}
const int* GetAge()
{
return age;
}
};
int main()
{
int aNum = 10;
MyClass firstClass(&aNum);
cout << "First attempt: " ;
cout << *firstClass.GetAge() << endl;
return 0;
}
Or Scenario 2:
#include <iostream>
using namespace std;
class MyClass
{
private:
int* age;
public:
MyClass(const int &initData)
{
cout << "In default constructor working on pointers" << endl;
age = new int;
(*age) = (initData);
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete age;
}
const int* GetAge()
{
return age;
}
};
int main()
{
MyClass firstClass(10);
cout << "First attempt: " ;
cout << *firstClass.GetAge() << endl;
return 0;
}
I Would think solution 2, as that uses reference to memory and thus speeds up the execution?
Thanks for the assistance already, and sorry for the long post...
First: you can not set a const pointer to a non-const pointer, you can circumvent this using a const_cast<int*>(initData) which gets rid of the const-ness of initData when assigning to age.
But i do not think this is what you want to achieve.
So first of all a pointer is just pointing to memory - that memory must therefore be managed by someone else than the pointer. Usually you only need a pointer if you want to reference something or iterate - if you intend to be the owner of that memory you might not want to use a pointer.
Secondly: if you start learning C++ now, try to learnt 'modern' C++ and utilize smart_pointers (see smart pointers form cppreference).
A rule of thumb: if you do not necessarily need a pointer (no need for iteration, direct memory access) use by reference instead.
But bottom line: your example looks like it is not meant to be used with pointers at all. Just store the int value.
class MyClass
{
private:
int age;
public:
// pass by const reference, this is cheap and good practice
MyClass(const int& initData)
{
cout << "In default constructor working on pointers" << endl;
// here the value of initData is actually copied into age
age = initData;
}
And if you really want to try pointers: start with the std::shared_ptr which is a ref-counting pointer easy to use.
Example:
#include <memory>
#include <iostream>
class test
{
private:
std::shared_ptr<int> age;
public:
// cheap and quick const ref
test(const std::shared_ptr<int>& data)
{
age = data;
}
void print()
{
std::cout << *age << std::endl;
std::cout << "Use count: " << age.use_count() << std::endl;
}
};
int main()
{
// here we store the data
int i = 17;
// here we have the shared_ptr
std::shared_ptr<int> p = std::make_shared<int>(i);
// here we pass it to the object
test t(p);
t.print();
return 0;
}
It's a long time ago since my last c++ project and now I'm stuck in a very simple problem. I create two objects and want to modify only one of them. Now I don't understand why the other object is also modified...
MainClass:
#include "testobject.h"
#include <iostream>
int main() {
TestObject o1;
TestObject o2;
std::cout << "object1 before: " << o1.getI() << std::endl;
std::cout << "object2 before: " << o2.getI() << std::endl;
o1.setI(2);
std::cout << "object1 after: " << o1.getI() << std::endl;
std::cout << "object2 after: " << o2.getI() << std::endl;
}
TestObjectClass:
#include "testobject.h"
int i;
int TestObject::getI() {
return i;
}
void TestObject::setI(int j) {
i = j;
}
The output is:
object1 before: 0
object2 before: 0
object1 after: 2
object2 after: 2
Why is i in object2 also set to 2?
The both objects refer to the common variable
int i;
declared in the global namespace. So once the variable is changed the class method
int TestObject::getI() {
return i;
}
will return the same value of the variable i for both objects.
Make the variable a data member of the class.
For example
class TestObject
{
//...
private:
int i;
};
Pay attention to that the member function getI should be declared with the qualifier const because it does not change the object itself
class TestObject
{
public:
int getI() const {
return i;
}
//...
};
The task is to create class, which counts the objects of its type, in every moment. Here is my code. The errors are:
1. the object has type qualifiers that are not compatible with the member function "counter::print";
2. return value type does not match the function type; - this was obwious really!
I corrected the errors and it gives me new one that I can't fix;
1. 'void counter::print(void)': cannot convert 'this' pointer from 'const counter' to 'counter &'
class counter {
private:
static int count;
public:
counter();
counter(const counter &from);
void print() const;
~counter();
};
counter::counter() {
++count;
}
counter::counter(const counter &from) {
++count;
cout << "Copy constructor:\t";
from.print(); // here is the error
}
void counter::print() const{
cout << "\t Number of objects = " << count << endl;
}
counter::~counter() {
--count;
cout << "Destructor:\t\t";
print();
}
int counter::count = 0;
counter f(counter x);
void main() {
counter c;
cout << "After constructing of c:";
c.print();
cout << "Calling f()" << endl;
f(c);
cout << "After calling f():";
c.print();
}
counter f(counter x) {
cout << "Argument inside f():\t";
x.print();
return x;
}
Firstly, change:
void print();
to:
void print() const;
because (a) it's a const method anyway and (b) you're trying to call it in a const context within your constructor.
For the second error here:
void f(counter x) {
cout << "Argument inside f():\t";
x.print();
return x; // 2 - nd error
}
it should be fairly obvious that you can't return a value from a void function. Either change it to:
counter f(counter x) {
cout << "Argument inside f():\t";
x.print();
return x;
}
or simply don't return anything:
void f(counter x) {
cout << "Argument inside f():\t";
x.print();
}
void print();
You have declared a non-const member function, which means it cannot be called by const instances.
from.print(); // 1 - st error
Here the type of from is const counter& which means it cannot call the print function. Instead make your print function const.
void print() const;
void counter::print() const { ... }
return x; // 2 - nd error
Why are you returning anything from a function with a void return type?
#include <iostream>
using namespace std;
class Machine
{
class State *current;
public:
Machine();
void setCurrent(State *s)
{
current = s;
}
void on();
void off();
};
class State
{
public:
virtual void on(Machine *m)
{
cout << " already ON\n";
}
virtual void off(Machine *m)
{
cout << " already OFF\n";
}
};
void Machine::on()
{
current->on(this);
}
void Machine::off()
{
current->off(this);
}
class ON: public State
{
public:
ON()
{
cout << " ON-ctor ";
};
~ON()
{
cout << " dtor-ON\n";
};
void off(Machine *m);
};
class OFF: public State
{
public:
OFF()
{
cout << " OFF-ctor ";
};
~OFF()
{
cout << " dtor-OFF\n";
};
void on(Machine *m)
{
cout << " going from OFF to ON";
m->setCurrent(new ON());
delete this;
}
};
void ON::off(Machine *m)
{
cout << " going from ON to OFF";
m->setCurrent(new OFF());
delete this;
}
Machine::Machine()
{
current = new OFF();
cout << '\n';
}
int main()
{
void(Machine:: *ptrs[])() =
{
Machine::off, Machine::on
};
Machine fsm;
int num;
while (1)
{
cout << "Enter 0/1: ";
cin >> num;
(fsm. *ptrs[num])();
}
}
There are a few bits of code I don't completely understand.
First, what does this do exactly?
(fsm. *ptrs[num])();
It looks like it's calling a default constructor of state, but I am not totally sure. Also, I don't understand where the on and off method is called. I think the object machine is the calling object for the on and off method, but I am not even sure.
Lastly, why do we destroy this?
void on(Machine *m)
{
cout << " going from OFF to ON";
m->setCurrent(new ON());
delete this;
}
Is it only for memory management?
I have rewritten the code with two function pointers and some comments:
Instead of array of function pointers, I have used 2 diff pointers and I am using if else for making the decision for switching state.
Main:
int main()
{
void (Machine::*offptr)() = &Machine::off; //offptr is a member funct pointer that now points to Machine::off function
void (Machine::*onptr)() = &Machine::on; //onptr is a member funct pointer that now points to Machine::on function
Machine fsm;
int num;
while (1)
{
cout<<"Enter 0/1: ";
cin>>num;
if( num == 0 )
{
(fsm.*offptr)(); //Here your are calling the function pointed to by the offptr (i.e., Machine::off) using the pointer
}
else if( num == 1 )
{
(fsm.*onptr)(); //Here your are calling the function pointed to by the onptr (i.e., Machine::on) using the pointer
}
}
}
In your example, all the decision is taken with the help of pointer array indices it self. So if user presses 0 the function pointed by ptrs[0] will be called and for 1 the function pointed by ptr[1] will be called. But since there is no check to make sure the user entered 0/1, the program will crash if the user enters something other than 0 or 1.
void on(Machine *m)
{
cout << " going from OFF to ON";
m->setCurrent(new ON()); //Here you are changing the state of the machine from OFF to ON (Note: call comes to this function only if the previous state was OFF).
delete this; //The previous state instance (OFF state pointed by this pointer) of the machine is no more required. So you are deleting it.
}
I would like some help in returning references to objects created in the heap.
I am reading a book titled Sam's Teach Yourself C++ and in chapter 12, the author introduces returning references to objects on the heap. The example illustrates a memory leak, and the author says that one of the solutions is to declare the object in the calling function and then to pass it to TheFunction() by reference.
This is the example:
// Listing 12.5
// Resolving memory leaks
#include <iostream>
class SimpleCat
{
public:
SimpleCat (int age, int weight);
~SimpleCat() {}
int GetAge() { return itsAge; }
int GetWeight() { return itsWeight; }
private:
int itsAge;
int itsWeight;
};
SimpleCat::SimpleCat(int age, int weight):
itsAge(age), itsWeight(weight) {}
SimpleCat & TheFunction();
int main()
{
SimpleCat & rCat = TheFunction();
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
std::cout << "&rCat: " << &rCat << std::endl;
// How do you get rid of that memory?
SimpleCat * pCat = &rCat;
delete pCat;
// Uh oh, rCat now refers to ??
return 0;
}
SimpleCat &TheFunction()
{
SimpleCat * pFrisky = new SimpleCat(5,9);
std::cout << "pFrisky: " << pFrisky << std::endl;
return *pFrisky;
}
My attempt:
#include <iostream>
class SimpleCat
{
public:
SimpleCat(int age, int weight);
~SimpleCat() {}
int GetAge() { return itsAge; }
int GetWeight() { return itsWeight; }
private:
int itsAge;
int itsWeight;
};
SimpleCat::SimpleCat(int age, int weight):
itsAge(age), itsWeight(weight) {}
SimpleCat* TheFunction(SimpleCat&);
int main()
{
SimpleCat * rCat;
rCat = TheFunction(rCat);
int age = rCat->GetAge();
std::cout << "rCat is " << age << " years old!\n";
std::cout << "rCat: " << rCat << std::endl;
delete rCat;
rCat = 0;
system("PAUSE");
return 0;
}
SimpleCat* TheFunction(SimpleCat& rCat)
{
rCat = new SimpleCat(5, 9);
std::cout << "rCat: " << rCat << std::endl;
return rCat;
}
Second Attempt
#include <iostream>
using namespace std;
class SimpleCat
{
public:
SimpleCat(int age, int weight)
{
}
void setAge(int age)
{
itsAge = age;
}
void setWeight(int wgt)
{
itsWeight = wgt;
}
~SimpleCat() { cout << "Object is being deleted" << endl; }
int GetAge() { return itsAge; }
int GetWeight() { return itsWeight; }
private:
int itsAge;
int itsWeight;
};
//SimpleCat * TheFunction();
SimpleCat& TheFunction(SimpleCat* rCat)
{
rCat = new SimpleCat(5,9);
//pFrisky->setAge(5);
//pFrisky->setWeight(9);
return *rCat;
}
int main()
{
SimpleCat * rCat;
SimpleCat & rCat = TheFunction(&rCat);
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
This could work (in the sense, compile), but is actually wrong:
SimpleCat TheFunction()
{
rCat = new SimpleCat(5,9);
// do something with rCat if you want
return *rCat;
}
int main()
{
SimpleCat rCat = TheFunction();
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
Here, you create the new object and return a reference to it to initialize the other object, which is legit, because every C++ class has a copy constructor by default. However, you'll get a memory leak here, because you create new object which is never deleted afterwards.
This can be a better version:
void TheFunction(SimpleCat*& rCat)
{
if (rCat!=NULL) delete rCat;
rCat = new SimpleCat(5,9);
// do something else with rCat if you want
return; //not required
}
int main()
{
SimpleCat * rCat = NULL;
TheFunction(rCat);
int age = rCat->GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
Here, you initialize the new pointer by reference(which is also legit). When you declare the pointer, you declare the variable, which has an address, but doesn't have a sensible content yet. You give the reference to that address to your function, so you don't have to return anything. After the function has initialized your reference, you can use it from your main program. No memory will be leaked here, but only as long as all new pointers are initialized with NULL. So potentially this might cause problems too, if your pointer is somehow pointing to a garbage.
The third version (the safest) would be:
void TheFunction(SimpleCat& rCat)
{
rCat.age = 5;
rCat.weight = 9;
}
int main()
{
SimpleCat rCat;
TheFunction(rCat);
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
There you give the reference to the new object to the function which will initialize it (i.e. assign some values to its members). The object already exists since the moment it's declared (only initialized by garbage by default), so this is also legit. No memory leak here either, because you don't claim memory for any new object.
SimpleCat * rCat;
SimpleCat & rCat = TheFunction(&rCat);
I don't think these lines are going to do what you think they do.
The first line is declaring a variable rCat that is a pointer to a cat, but never constructing a cat to go with it. The second is going to not work because you're declaring the same variable again. (can't have 2 rCat objects).
I'm still not quite sure what you're trying to do, though.
SimpleCat rCat;
TheFunction(&rCat);
and don't do:
rCat = new SimpleCat(...)
In TheFunction, just do the SetAge/SetWeight calls like you have them.
No leaks because you never called new. Of course, TheFunction no longer needs to return anything either because it's just modifying the object that was passed in. I'm not sure if that demonstrates what the author was trying to get to, though.
I think to demonstrate what the author wants, you'd change your TheFunction to be:
void TheFunction(SimpleCat& rCat) {
rCat.SetAge(5);
rCat.SetWeight(9);
}