Scope of object created using new - c++

I am learning C++ as a hobby and am wrestling with using "new" to dynamically create a class object. I have read that dynamically created classes do not lose scope, but that does not seem to work for my simple example.
When executed, the value of 'testValue1' is set to 555 in the constructor and printed. When the control is returned to main, 'testvalue' is unfortunately set to 0 (or not defined--not sure). I can set the value inside of main and the value is properly maintained inside of main as well as in a for loop.
The problem: I don't understand why the initialized value of 555 is not maintained when control is returned to main. I know I am doing something wrong or not understanding scope for dynamically assigned class object properly...any assistance is appreciated. Here is the sample code:
//main.cpp
#include <iostream>
using namespace std;
class generalVars
{
private:
public:
//data attributes
int testValue1;
//constructor
generalVars()
{
cout << "I am in general vars constructor" << endl;
int testValue1= 555;
cout << "testValue1 has been set " << testValue1 << endl;
}
~generalVars(void)
{
cout << "I am in general vars destructor" << endl;
};
};
int main(int argc, char *argv[])
{
cout << "I am in Main" << endl;
generalVars* myGeneralVars = new generalVars; //create on heap
cout << "Main1 testvalue1 = " << myGeneralVars->testValue1 << endl;
myGeneralVars->testValue1 = 777;
cout << "Main2 testvalue1 = " << myGeneralVars->testValue1 << endl;
for (int i=0; i<= 3; i++)
{
cout << "Inside while loop..." << endl;
cout << "Main3 " << i << " testvalue1 = " << myGeneralVars->testValue1 << endl;
}
delete myGeneralVars; //delete from heap
return 0;
}

This statement:
int testValue1= 555;
declares a local variable, distinct from the data member of the same name.
So it doesn't change the value of the member.
Instead, do e.g.
testValue1= 555;
Or use the constructor's memory initializer list, like this:
generalVars()
: testValue1( 555 )
{
cout << "I am in general vars constructor" << endl;
cout << "testValue1 has been set " << testValue1 << endl;
}

You defined another variable in generalVars constructor and init value to 555, to init member testValue1, you don't need to define it again in constructor.
update
generalVars()
{
cout << "I am in general vars constructor" << endl;
int testValue1= 555; // this defines another testValue1 variable. it's different from member testValue1
cout << "testValue1 has been set " << testValue1 << endl;
}
to
generalVars()
{
cout << "I am in general vars constructor" << endl;
testValue1= 555; // Note, removed int
cout << "testValue1 has been set " << testValue1 << endl;
}

Two things are going on:
1) you re-declare testValue1 here by putting int in front:
generalVars()
{
cout << "I am in general vars constructor" << endl;
int testValue1= 555; //right here!
cout << "testValue1 has been set " << testValue1 << endl;
}
This hides the class's own instance of testValue1 with a new unique variable by the same name. You can reference both like so:
generalVars()
{
cout << "I am in general vars constructor" << endl;
int testValue1= 555; //note, still has int
cout << "testValue1 has been set " << testValue1 << endl;
cout << "this->testValue1 has not been set and is " << this->testValue1 << endl;
this->testValue1 = 555; //note, this->
cout << "this->testValue1 has been set " << this->testValue1<< endl;
}
Or you could avoid the name clash and refer to it normally:
generalVars()
{
cout << "I am in general vars constructor" << endl;
testValue1= 555; //note, no int. This is identical to this->testValue1
cout << "testValue1 has been set " << testValue1 << endl;
}
Next is not really an issue, but should be noted:
You do not need to heap allocate things with new in C++ most of the time. You should prefer stack allocated objects
generalVars myObject;
instead of:
generalVars *myObject = new generalVars();
...
delete myObject;
Or, in cases where you do want to create a heap allocated object:
auto myObject = std::make_unique<generalVars>();
Or, if you need multiple handles:
auto myObject = std::make_shared<generalVars>();
The unique_ptr and shared_ptr examples do not require explicit deletion. The heap allocation will be deleted when the pointer object goes out of scope. This especially helps with exception safety.

Related

Counting number of objects of different classes

I would like to count the number of objects that my program creates over its lifetime. Based on the solution provided here:
how to count the number of objects created in c++
I have the following code:
#include <iostream>
using namespace::std;
using std::cout;
using std::endl;
template <typename T>
struct counter
{
counter()
{
objects_created++;
objects_alive++;
}
virtual ~counter()
{
--objects_alive;
}
static int objects_created;
static int objects_alive;
};
template <typename T> int counter<T>::objects_created(0);
template <typename T> int counter<T>::objects_alive(0);
class X : counter<X>
{
int a;
};
class Y : counter<Y>
{
int b;
};
void fooX(class X x) {
cout << "passing object" << endl;
}
void fooY(class Y& y) {
cout << "passing reference" << endl;
}
int main()
{
cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
X x;
Y y;
cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
fooX(x);
fooY(y);
cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
int ui;
cin >> ui;
}
I expected that since x is passed by value, a copy of it is made inside fooX making the total number of objects of class X to be 2 while since y is passed by reference, the total number of objects of class Y to be 1.
Yet, the output of the code is as follows:
created: X:0 Y:0
alive: X:0 Y:0
created: X:1 Y:1
alive: X:1 Y:1
passing object
passing reference
created: X:1 Y:1
alive: X:0 Y:1
Why does not the number of Xs created be 2?
A copy constructor is automatically added to your counter class, and that automatically created copy constructor doesn't increment your static variables.
Write a copy constructor which does that:
counter(counter const&)
{
objects_created++;
objects_alive++;
}
Note that your destructor should probably not be virtual, unless you intend to delete dynamically created instances of derived classes via pointers or references to counter. As it stands, it's just premature pessimisation because it needlessly increases the size of your objects.

retrieving int value from void sub function to function in C++

I'm a foundation student who starting to learn coding C++. I'm doing a survey program for my college assignment and after the testing, i found out that the sum value from the sub function cannot sum up properly to the value in main function. any one HELP!!!
here is the code:
#include <iostream>
using namespace std;
int Q1();
int Q2();
int Q3();
int Q4();
int Q5();
int main()
{
char select;
int E, A, C, N, O;
int extroversion=0, agreeableness=0, conscientiousness=0, neuroticism=0, opennesstoexperience=0;
cout << "This is a Self-Esteem Questionnaire." << endl;
cout << "\nInsert S to start the test (Q to Quit): ";
cin >> select;
select=toupper(select);
if (select=='S')
{
cout << "------------------INSTRUCTIONS-----------------" << endl;
cout << "For each statement 1-50 mark how much you agree" << endl;
cout << "with on the scale 1-5, where " << endl;
cout << "1=disagree, 2=slightly disagree, 3=neutral, " << endl;
cout << "4=slightly agree and 5=agree " << endl;
cout << "-----------------------------------------------" << endl;
cout << Q1() << endl;
extroversion+=E;
cout << Q2() << endl;
agreeableness+=A;
cout << Q3() << endl;
conscientiousness+=C;
cout << Q4() << endl;
neuroticism+=N;
cout << Q5() << endl;
opennesstoexperience+=O;
cout << extroversion << endl;
cout << agreeableness << endl;
cout << conscientiousness << endl;
cout << neuroticism << endl;
cout << opennesstoexperience << endl;
}
else
if(select=='Q')
{
cout << "Program quit!" << endl;
}
return 0;
}
int Q1()
{
int E=0;
cout << "I am the life of the party." << endl;
cout << "1=disagree, 2=slightly disagree, 3=neutral," << endl;
cout << "4=slightly agree and 5=agree" << endl;
cout << "\nRating: ";
cin >> E;
return E;
}
int Q2()
{
int A=0;
cout << "I feel little concern for others." << endl;
cout << "1=disagree, 2=slightly disagree, 3=neutral," << endl;
cout << "4=slightly agree and 5=agree" << endl;
cout << "\nRating: ";
cin >> A;
return A;
}
int Q3()
{
int C=0;
cout << "I am always prepared." << endl;
cout << "1=disagree, 2=slightly disagree, 3=neutral," << endl;
cout << "4=slightly agree and 5=agree" << endl;
cout << "\nRating: ";
cin >> C;
return C;
}
int Q4()
{
int N=0;
cout << "I get stressed out easily." << endl;
cout << "1=disagree, 2=slightly disagree, 3=neutral," << endl;
cout << "4=slightly agree and 5=agree" << endl;
cout << "\nRating: ";
cin >> N;
return N;
}
int Q5()
{
int O=0;
cout << "I have a rich vocabulary." << endl;
cout << "1=disagree, 2=slightly disagree, 3=neutral," << endl;
cout << "4=slightly agree and 5=agree" << endl;
cout << "\nRating: ";
cin >> O;
return O;
}`
Let's start by reducing this problem to its essentials.
int main()
{
int E;
int extroversion=0;
cout << Q1() << endl;
extroversion+=E;
cout << extroversion << endl;
return 0;
}
int Q1()
{
int E=0;
cout << "Give me a number" << endl;
cin >> E;
return E;
}
The problem is that the variable E you have declared in Q1, has nothing to do with the variable E you have declared in main. Therefor when you write:
extroversion+=E;
you are using an uninitialized variable. The solution is to rewrite main as:
int main()
{
int extroversion=0;
int E = Q1(); // Capture the result of Q1 in E
cout << E << endl;// ... *then* print it.
extroversion+=E; // And now you can use the value of E in this function.
cout << extroversion << endl;
return 0;
}
Please note: That "reduced" problem is what you should have posted in the first place - we don't need to see the masses of text, and we certainly don't need to see you do the same thing five times. Remove the verbiage (and check that you still have the problem), and then post the reduced problem.
You're using a truck load of uninitialised variables in main. You are returning values back from the various Q functions, which are being used by the cout calls, but you are not setting E, A, C, N, O in main. Formally this means that the behaviour of your program is undefined.
Replace
cout << Q1() << endl;
with
cout << (E = Q1()) << endl;
and so on, and all will be well. See for yourself by using your line by line debugger.
Let's start from the beginning (which I think your might want to do to learn C/C++, perhaps by running through one of the many online C++ tutorials). I think your main focus should be on the following (in no specific order):
Initialization: Primitive data types like int, char, etc. are called Plain Old Datatypes (POD). In all the cases you are using in your code, they are not initialized, following the rule "don't pay for what you don't use." See What are POD types in C++? for more info.
Scope: Variables exist within a region of a program defined by where they are declared. For example, in main() you declare int E; (without initializing it so it simply acquires the value of whatever was in memory at that location). The scope of this E in main() starts where it is declared at ends at the end of main() (its scope is the function main).. Now we go to your function int Q1() in which you declare int E = 0;. At that point in the function this E comes into existence where it is declared and then goes out of existence at the end of Q1 (its scope is the function Q1). When you set E in Q1 that variable (and its value) disappears when you exit Q1, and so back in main when you add E, you are adding the E declared in main which just has a random value. Thus the E you used in main
extroversion+=E;
is not the same E you set in Q1
cin >> E;
They are different variables.
See https://www.tutorialspoint.com/cplusplus/cpp_variable_scope.htm for more info.
Functions: You are calling functions which return a value, but you don't use that returned value. I think that your misunderstanding of the scope of variables and the concept of a function is the root of your difficulties. Frex, in Q1() you return the value of E, which is indeed what you want. You just didn't know how to use it. In this instance, I would replace
cout << Q1() << endl;
extroversion+=E;
with
extroversion = Q1();
See http://www.cplusplus.com/doc/tutorial/functions/ for more info.
There are many issues with your code above that I think could be rectified by visiting some online tutorials like those I have referenced. I could rewrite your code but I think that (1) it should probably work with the suggestions I have given here and (2) you will learn more if you rewrite it yourself! :-) It also appears to me that you may have just kept adding things in order to get your code to compile that are not necessary. I might suggest that you go through each line and ensure that you understand why it is there (and why it is where it is).

Redefining a corrupted reference

class A
{
};
int main()
{
A *a= new A(); // variable "a" must be pointer, I can't edit this line
A& b = *a; //b must be a reference
delete a; //deletion
a= new A(); //re-definition
//b is now corrupted.
}
In a piece of code that I have to work with, a pointer to an object of class A is created and a reference to this pointer too.
For some reasons, I have to delete the pointer and re-defined it. How can I get b to work again ?
You can do this, subject to some constraints:
A* a = new A(); // variable "a" must be pointer, I can't edit this line
A& b = *a; // b must be a reference
a->~A(); // destroy first object
new (a) A(); // create second, new object in its place
delete a; // destroy second object and release memory
The constraints are if A contains non-static const data members, you cannot use b after the reconstruction.
(Starting with C++17, you can reuse a reconstructed object even if it has const members by using some extra acrobatics: A& b2 = *std::launder(a); But you still cannot reuse b as is.)
in your code you are not using a reference to a pointer, to do so:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int* ptrA = new int(77);
int*& rPtrA = ptrA; // this a reference to a pointer
cout << "ptrA: " << ptrA << endl;
cout << "*ptrA: " << *ptrA << endl;
cout << "rPtrA: " << rPtrA << endl;
cout << "*rPtrA: " << *rPtrA << endl;
delete ptrA;
ptrA = NULL;
cout << "ptrA: " << ptrA << endl;
// cout << "*ptrA: " << *ptrA << endl; // cause runtme error
cout << "rPtrA: " << rPtrA << endl;
// cout << "*rPtrA: " << *rPtrA << endl;// cause runtme error
ptrA = new int(100);
cout << "ptrA: " << ptrA << endl;
cout << "*ptrA: " << *ptrA << endl;
cout << "rPtrA: " << rPtrA << endl;
cout << "*rPtrA: " << *rPtrA << endl;
delete rPtrA; // delete pointer through its reference
rPtrA = NULL;
cout << "ptrA: " << ptrA << endl;
// cout << "*ptrA: " << *ptrA << endl; // runtime error
cout << "rPtrA: " << rPtrA << endl;
// cout << "*rPtrA: " << *rPtrA << endl; // runtime error
return 0;
}
&* is used for reference to pointer not just &.
a reference is a just another pseudonym to a variable so whatever the variable changes the reference changes also.
a reference to a pointer REFERS to the POINTER'S ADDRESS not the address the pointer stores (value of pointer).
in your code you used a reference to the value(what pointer stores not the pointer itself) the pointer points to

What do conditionals do to polymorphic objects in C++? (inclusion polymorphism)

I ran into an interesting error and I'm pretty sure it has to do with inclusion polymorphism in the context of conditional statements.
The highlights of the example are as follows:
ClassParent *parentPointer; //Declare pointer to parent
if(condition){
ClassChild1 = mychild; //Declare child1 object
parentPointer = *mychild;//Parent pointer points to child
}
if(!condition){
ClassChild2 = mychild; //Declare child2
parentPointer = *mychild;//Parent pointer points to child2
}
cout << *parentPointer; //What will this point to???
As should be clear, the conditional statements make *parentPointer variable in the last line.
My whole function looks like this: (Note where it crashed)
void PosApp::addItem(bool isPerishable) {
Item *refitem;
if (isPerishable) {
Perishable myitem;
std::cout << "Enter the following: " << std::endl
<< "Sku: " << std::endl
<< "Name:" << std::endl
<< "Price: " << std::endl
<< "Taxed: " << std::endl
<< "Quantity: " << std::endl
<< "Expiry date: " << std::endl;
std::cin >> myitem;
refitem = &myitem; //Item now implements inclusion polymorphism, be aware of dynamic/static types (dynamic is item, static Perishable)
}
if (!isPerishable) {
NonPerishable myitem;
std::cout << "Enter the following: " << std::endl
<< "Sku: " << std::endl
<< "Name:" << std::endl
<< "Price: " << std::endl
<< "Taxed: " << std::endl
<< "Quantity: " << std::endl;
std::cin >> myitem;
refitem = &myitem; //Item now implements inclusion polymorphism, be aware of dynamic/static types (dynamic is item, static NonPerishable)
}
if (cin.fail()) {//The inclusion polymorphism allows me to call this block only once regardless of persh/non-perishable
cin.clear();
cin.ignore(2000, '\n');
//CRASH POINT***********
cout << "Error: " << *refitem << endl;//Be aware of early/late binding, the write/dowrite must be child calls, not parent.
}
}
Now the very interesting thing, is when removed the if() on cin.fail and forced an error in the input, it works. The code looks like this now:
void PosApp::addItem(bool isPerishable) {
Item *refitem;
if (!isPerishable) {
NonPerishable myitem;
std::cout << "Enter the following: " << std::endl
<< "Sku: " << std::endl
<< "Name:" << std::endl
<< "Price: " << std::endl
<< "Taxed: " << std::endl
<< "Quantity: " << std::endl;
std::cin >> myitem;
refitem = &myitem; //Item now implements inclusion polymorphism, be aware of dynamic/static types (dynamic is item, static NonPerishable)
cin.clear();
cin.ignore(2000, '\n');
//THIS DOES NOT CRASH NOW
cout << "Error: " << *refitem << endl;//Be aware of early/late binding, the write/dowrite must be child calls, not parent.
}
The best answer I could come up with, in terms of the crash, is that somehow when the scope resolved in the first code snippet, the program lost the contents of the pointer.
This question is two fold: Can you implement inclusion polymorphism in the context of conditionals (as shown) and, if not, is this what caused my program to crash?
Note: I did not include the entire program (because it is hundreds of lines) but suffice to say, when I changed to code into the second snippet, the behavior is what should be expected.
Objects with automatic storage are local to the { } braces around them, including the if statement. If you have a pointer to a local, and the object goes out of scope, accessing that pointer is UB.
Object* ptr;
if (condition)
{
Object obj;
ptr = &obj;
} //obj is out of scope
*ptr; //undefined behaviour
This is what you are doing with setting refitem to point to local objects. Instead, create a Perishable* or NonPerishable* by using new, and when the block ends, assign that pointer to refitem. The polymorphism will work as you expect, the error was just the scope of objects.
if (!isPerishable)
{
NonPerishable* myitem = new NonPerishable(); //dynamic memory
std::cin >> *myitem;
refitem = myitem; //refitem is still valid after this scope ends
}

C++ no operator "<<" match these operand (inheritance)

I have just recently started class inheritance in c++. While I was making a "Test" program, a error occurred with the cout statement. No clue how to fix it and would be appreciate your response.
#include <iostream>
using namespace std;
class Power{
public:
void isWeak(){
cout << " Weak"<< endl;
}
void isStrong(){
cout << " Strong" << endl;
}
};
class Person:public Power{};
class Person2:public Power{};
int main(){
Person human;
Person2 human2;
cout << "Human is " << human.isWeak() << endl; //error
cout << "Human 2 is " << human2.isStrong() << endl; //error
system("pause");
return 0;
}
the main()'s cout statement has that error between the output and human
Change the functions to
char const *isWeak(){
return " Weak";
}
char const *isStrong(){
return " Strong";
}
As currently defined, both functions have void return type, which means the cout statements within main are trying to print void, which doesn't make sense, and is the cause of the error.
You are attempting to print a void:
cout << "Human is " << human.isWeak() << endl;
is the same as typing
cout << "Human is " << void << endl;
Which will not compile. What you need to do is define your functions in either of the following ways:
class Power
{
public:
std::string isWeak()
{
return std::string(" is weak");
}
std::string isStrong()
{
return std::string(" is strong");
}
};
Or, change your code:
cout << "Human is ";
human.isWeak();
cout << endl;
cout << "Human 2 is ";
human2.isStrong();
cout << endl;
Problem is with isWeak() and isStrong() return type. these two functions return void and you are trying to print it. you can try this-
cout << "Human is " ;
human.isWeak();
cout << endl;
cout << "Human 2 is " ;
human2.isStrong();
cout << endl;
You're trying to 'print' a 'void' statement in cout << "Human is " << human.isWeak() << endl;
You'll need to change your isWeak and isStrong functions to return a std::string/const char* or change the way you call them:
to string:
const char* isWeak() {
return " Weak";
}
// then you can do
cout << "Human is " << human.isWeak() << endl;
Or change the way you call the function:
cout << "Human is ";
human.isWeak();
Your isWeak and isStrong functions are void they do not return anything; calling cout << human.isWeak() is expecting isWeak to return something (an int, string, double, etc.).