As a new C++ hobbyist, I am still wrestling with understanding scope for class object created using "new". I thought I read that by instantiating a dynamic object using "new", the class (and members) would be accessible by all parts of the program directly (for example, within other functions) since it is not created on the stack.
In the code below, I set the initial value of 'tesValue1' to "111" in the constructor, and then try to update it to "222" in the 'check_accessibility' function. This fails to compile with the error "myGeneralVars" not declared within this [the function call] scope.
Any assistance is greatly appreciated.
//main.cpp
#include <iostream>
using namespace std;
class generalVars
{
private:
public:
//data attributes
int testValue1;
//constructor
generalVars()
{
testValue1= 111;
}
~generalVars(void)
{
cout << "destructor code here" << endl;
};
};
void check_accessibility() {
myGeneralVars->testValue1= 222;
}
int main(int argc, char *argv[])
{
generalVars* myGeneralVars = new generalVars; //create on heap
cout << "Main testvalue1 = " << myGeneralVars->testValue1 << endl; //value set in constructor
check_accessibility(); //sets testValue to new value
cout << "Main testvalue1 = " << myGeneralVars->testValue1 << endl; //want "222"
delete myGeneralVars; //delete from heap
return 0;
}
It has the lifetime you decide.
C++ uses the concept of storage duration: The lifetime of an object depends on where and how its instantiated. There are three (Four) types of storage durations:
Static storage duration: The object will be initialized at program start and will be destructed at program finish. Global variables and static class attributtes have static storage duration.
Automatic storage duration: The lifetime of an object is defined by the lifetime of the scope the variable is declared in. So the lifetime of local variables starts when the function starts, and ends when the function ends. The same for non-static class data members: Its lifetime starts when the object's lifetime starts, and ends when the lifetime of the object ends.
Dynamic storage duration: The object is created on dynamic memory using new and delete, and the lifetime is determined by the user. When the user does new the lifetime starts, and when does deletethe lifetime ends.
See this documentation page for more information.
In your case, you instantiate an object with dynamic storage duration, using a pointer variable to hold its memory address (The location of the object). Since you never do a delete on that pointer, the lifetime of the object never ends: Thats a memory leak.
Also, you try to access a variable defined in one function (main) in other function (check_accessibility). Of course that variable is not visible out of main. But thats nothing to do with dynamic storage duration, its only a simple name lookup problem. Whoever tells you storage duration has something related or depending on name/variable accessibility was completely wrong.
Since you're a hobbyist and a beginner, let's get you on the right track early so that you get more pleasure and enjoyment from your hobby.
consider the changes I have made here employing principles that will make your program more elegant, robust and pleasing as it grows in complexity.
//main.cpp
#include <iostream>
#include <memory>
using namespace std;
class generalVars
{
private:
public:
//data attributes
int testValue1;
//constructor
generalVars()
: testValue1(111)
{
}
~generalVars(void)
{
// if the class is carefully written using std:: objects
// you will rarely need to define a destructor
cout << "destructor code here" << endl;
};
};
// pass a reference to a mutable object to ensure that logic
// is performed on the object and not on its lifetime
void check_accessibility(generalVars& gv) {
gv.testValue1= 222;
}
int main(int argc, char *argv[])
{
unique_ptr<generalVars> myGeneralVars(new generalVars); //create on heap *safely*
cout << "Main testvalue1 = " << myGeneralVars->testValue1 << endl; //value set in constructor
check_accessibility(*myGeneralVars); //sets testValue to new value
cout << "Main testvalue1 = " << myGeneralVars->testValue1 << endl; //want "222"
// no delete necessary - unique_ptr's destructor takes care of it
return 0;
}
output:
Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1
Executing the program....
$demo
Main testvalue1 = 111
Main testvalue1 = 222
destructor code here
myGeneralVars is not known by your function check_accessibility(), so you cannot access the variable. Instead, try to pass it as parameter.
void check_accessibility(generalVars* genVar) {
genVar->testValue1= 222;
}
int main(int argc, char *argv[])
{
generalVars* myGeneralVars = new generalVars; //create on heap
cout << "Main testvalue1 = " << myGeneralVars->testValue1 << endl; //value set in constructor
check_accessibility(myGeneralVars); //sets testValue to new value
cout << "Main testvalue1 = " << myGeneralVars->testValue1 << endl; //want "222"
delete myGeneralVars; //delete from heap
return 0;
}
myGeneralVar is valid only inside the main() scope, so check_accessibility() has no access to it. You have to declare it before, either in global scope (outside function definition) or by passing it as argument to check_accessibility() inside main(). Keep in mind that the main function is not the global scope, as you might think. main() is just a function like others and has its own scope.
In function check_accessibility you use name myGeneralVars that was not yet declared.
void check_accessibility() {
myGeneralVars->testValue1= 222;
}
So the compiler issues athe error.
Before using any name it has to be declared.
You could write the function the following way
void check_accessibility( generalVars* myGeneralVars ) {
myGeneralVars->testValue1= 222;
}
and call it as
check_accessibility( myGeneralVars );
Also, you can define the check_accessibility() function inside generalVars class and call it from main as
mygeneralVars->check_accessibility();
Related
I have created an object of a class inside a function. The created object is passed as a parameter to another class. I expect that when I exit the function in which the object is created, the object must be destroyed.
Also any references to this object must be invalid, but I find that the object referenced after exiting the function is still valid. Trying to understand the scope of the object. The code snipped is given below.
class TextWidget
{
public:
TextWidget()
{
cout << "Constructor TextWidget" << endl;
}
TextWidget(int id)
{
_ID = id;
cout << "Constructor TextWidget" << endl;
}
~TextWidget()
{
cout << "Destructor TextWidget" << endl;
}
void printWidgetInstance()
{
cout << this << endl;
}
int _ID;
};
class AnotherWidget
{
public:
AnotherWidget()
{
cout << "Constructor AnotherWidget" << endl;
}
~AnotherWidget()
{
cout << "Destructor AnotherWidget" << endl;
}
TextWidget* getTextWidget()
{
return _textWidget;
}
void setTextWidget(TextWidget* t)
{
_textWidget = t;
}
int getTextID() { return _textWidget->_ID; }
private:
TextWidget* _textWidget;
};
ButtonWidget b;
AnotherWidget a;
void fun()
{
TextWidget t(7);
b.setTextWidget(&t);
a.setTextWidget(&t);
a.getTextWidget()->printWidgetInstance();
b.getTextWidget()->printWidgetInstance();
}
int main()
{
fun();
cout << "TextWidget in AnotherWidget is ";
a.getTextWidget()->printWidgetInstance();
cout << "Text ID in a is " << a.getTextID() << endl;
getchar();
return 0;
}
OUTPUT
Constructor AnotherWidget
Constructor TextWidget
Before deleting TextWidget in class ButtonWidget 0x73fdf0
Before deleting TextWidget in class AnotherWidget 0x73fdf0
0x73fdf0
0x73fdf0
Destructor TextWidget
TextWidget in AnotherWidget is 0x73fdf0
Text ID in a is 7
A variable declared using automatic storage duration (not using new) has a lifetime of its scope. Accessing the variable outside the scope results in undefined behavior.
You need to understand what classes, objects, pointers and references are. Classes are code in memory, this code deals with the member variables. A class does not occupy any data memory. When you create a object you instantiate the class. This step will reserve some data memory for the local data of one object instance of the class. To access this instance you get a reference to the object (this). An object variable holds a pointer to the data memory of an instance of a class.
When an object gets destroyed the occupied memory block gets listed as free but not cleared. So if you still have a reference to that memory block you may access it. And as long as the system doesnt use this memory block for other purposes you still will find your bits and bytes there.
You may declare some variables:
long long_array[10];
myclass myobject;
These variables are stored sequential in one memory block. When you now access the memory behind the long_array through that array:
long_array[10] = 12345; // valid range is from long_array[0] to long_array[9]
Than you will overwrite the data of the object myobject.
I'm trying to learn C++, and from my understanding if a variable goes out of scope then it is destroyed and its memory is reallocated. If I have a class and it's method creates a variable, shouldn't that variable be destroyed after the method call? For example:
class TestClass {
public:
struct Pair{
std::string name;
int value;
};
void addPair() {
//should be deleted after push_back is called?
Pair x = Pair{ std::string{ "Test Object " }, counter++ };
pairs.push_back(x);
}
void printPairs() {
for (int i = 0; i < pairs.size(); i++) {
std::cout << "pair { " << pairs[i].name << " : " << pairs[i].value << " } " << std::endl;
}
}
void removePair() {
pairs.pop_back();
}
private:
int counter;
std::vector<Pair> pairs;
};
But when I tried addPair() then printPairs() then removePair() it works fine. Why doesn't it throw an error saying invalid access to memory location?
You said:
from my understanding if a variable goes out of scope then it is destroyed and its memory is reallocated.
That is correct. "reallocated" is not correct word I would use. I would phrase that as: The memory used by the object is available to be used by other objects.
And then you asked:
If I have a class and it's method creates a variable, shouldn't that variable be destroyed after the method call?
That is correct.
However, your situation is different.
When you use:
pairs.push_back(x);
a copy of x is placed in pairs. The copy continues to live in pairs after the function returns. Hence, printPairs() and removePair() work just fine.
First, access to variables out of scope is undefined behavior. The program might throw an error but it might even work well. So there's no guarantee an error will be raised.
Second, std::vector::push_back makes a copy of its arguments. So nothing to worry about when passing local variables to it.
Hi I read this definition on internet..
A destructor is a special member function of a class that is executed
whenever an object of it's class goes out of scope or whenever the
delete expression is applied to a pointer to the object of that class.
I tried this code..
#include <iostream>
using namespace std;
class Name{
public:
void Fun(){
cout << "Function" << endl;
}
Name(){
cout << "Constructor" << endl;
}
~Name(){
cout << "Destructor" << endl;
}
};
int main(){
Name obj;
obj.Fun();
cout << "End" << endl;
return 0;
}
It's calling destructor at the end of program..!! Mean object scope is the end of program? Sorry I'm little confused...
In your case the end of the scope of obj is at the end of the main function, but it could be any other scope depending on where you define obj. Example:
int main(){
// open a new scope here
{
// now 'obj' will be in the new scope
Name obj;
obj.Fun();
}
// the scope ended here, 'obj' destroyed now
cout << "End" << endl;
return 0;
}
You can find more information here, look at "Basic concepts" for "Scope" and "Lifetime".
Scope is a region in program that defines life time of objects defined within it. In nearly all cases it is defined by curly brackets. So when you have definition of function it's body defines a scope.
main is no special in any way in regard to definition of scope.
Some more cases:
int fun(){ // one scope
for(int i = 0; i < 1337; ++i){ // another scope
//note that i is defined within `for` scope not outside
}
if(true){ // same here
}
{ // you can even start and end scope at will
A a;
} // a will die here
{ // sometimes it is useful for redeclaring a variable, probably not best practice
A a; // this is legal
}
}
The object obj that you have created is a variable and as any variable it has scope. Scope is defined by curly brackets in which variable was created. In your case the scope of obj that you created is main function, because it is placed between curly brackets of that function. And when main function ends, your object is not available anymore (it is available only within that function) and that is why destructor is called.
You can also define scope of your own by just putting your object into curly brackets like that:
main(){
cout<<"scope of the main function"<<endl;
{
cout <<"scope where obj created"<<endl;
Name obj;
}
cout << "obj destroyed"<<endl;
cout << "End of main" <<endl;
}
In your case its C# program, In the case of object ends it availability after the program ends i.e. after the main is executed the object finds its destructor if it’s not available by programmer then its system generated destructor will be executed an it will destroy all the object and frees up the memory..
I am trying to call the constructor H, but for some reason its not being called.
I get no error when I compile my code, and I get the output:
A object initialized.
H object initialized.
If H was initialized properly, the cout from the constructor should also be shown.
Can someone please help? Thank you.
I also have another question. How can I change the value of hVec[i].a and have the value of
aArray[i].a take upon this value as well? I know I am suppose to use pointers, but an very confused. Sorry for all the questions; I'm reltaively new to programming in C++.
#include <vector>
#include <iostream>
struct A
{
A(int av):a(av){}
int a;
};
struct Heap
{
Heap(std::vector<A> hVal)
{
std::cout << "Constructor for H object. \n";
for (int i=0; i<hVal.size(); ++i)
{
hVec.push_back(hVal[i]);
std::cout << "hVec[i].a = " << hVec[i].a << " ";
}
std::cout << std::endl;
}
std::vector<A> hVec;
};
int main()
{
A a0(2), a1(4), a2(8);
std::vector<A> aArray;
aArray.push_back(a0);
aArray.push_back(a1);
aArray.push_back(a2);
std::cout << "A object initialized. \n";
Heap h(A);
std::cout << "H object initialized. \n";
return 0;
}
Your struct Heap does not have a constructor which takes A as argument.
However, you can initialize h with aArray which is std::vector<A> type
Heap h(aArray);
In C++, unless you are trying to be compatible with C, otherwise just use class instead of struct
Heap h(A);
This declares a function of type Heap(A) named h. Perhaps you meant:
Heap h(aArray);
This declares a local variable of type Heap named h.
use Heap h(aArray); instead of Heap h(A);
The line Heap h(A); declares a function h taking an object of type A as parameter, and returns an object Heap.
Static variables exist outside of the function, in terms of their memory at least (not scope), right? But one thing that always concerned me, is what happens when I call the function a second time. For instance:
f(){
static char buffer[256*256];
stuff(buffer);
}
When I call this function a second time, wouldn't it technically be declaring the variable 'buffer' a second time? Or does it work differently with static variables (as opposed to normal ones) once everything is compiled?
... I sometimes wish there was a chart or something of what a c++ compiler usually turns code into (minus optimizations) so I wouldn't have to bother you fine folks with little questions like this, aha. Thank you in advance!
edit: I know it works like this, I just want to know why though. It's probably something mind numbingly simple...
Static storage duration objects in function scope.
These objects are created on first use.
Then destroyed in reverse order of creation (with other static storage duration objects).
#include <iostream>
class X
{
public:
X(int x): m(x) {std::cout << "X: " << m << " created\n"; }
~X() {std::cout << "X: " << m << " destroyed\n";}
private:
int m;
};
static X x1(1);
int test()
{
std::cout << "Test: Start\n";
static X x3(3);
std::cout << "Test: Finished\n";
return 5;
}
int main()
{
std::cout << "Main: Start\n";
X x2(2);
test();
X x4(4);
std::cout << "Main: Finished\n";
}
Now Try it: (comments added). SSDO => Static Storage Duration object.
g++ X.cpp
./a.out
X: 1 created // SSDO file scope.
Main: Start
X: 2 created
Test: Start
X: 3 created // SSDO created on first use (Notice not destroyed)
Test: Finished
Test: Start // Notice not created here.
Test: Finished
X: 4 created
Main: Finished
X: 4 destroyed
X: 2 destroyed // Main now really finished. after destroying local variables.
X: 3 destroyed // Destroy SSDO in reverse order of creation. (3 - 1)
X: 1 destroyed
No, you static means that it is outside the scope of your function. It has the same effect as writing:
static char buffer[256*256];
f(){
stuff(buffer);
}
Except that the buffer is only visible in the scope of your function, and the code is more readable.
(NOTE: My example doesn't apply when char is not a primitive type - in that case, it is constructed the first time it is "declared").
In this context, static means that the variable has application lifetime. It is allocated before main() the function is entered, and deallocated after main() has returned. Also, its value is preserved between function calls. Think of it as a global variable that is only visible from inside that function.
The variable exists before and after you call the function...it's static.
This example might illustrate it:
#include <iostream>
using namespace std;
void test() {
static int i = 123;
if (i == 123) {
i = 321;
}
cout << i << endl;
}
int main(int arg, char **argv) {
test();
test();
return 0;
}
The output is:
321
321
So "i" is only initialized the first time it is encountered, so to speak. But actually it's allocated at compile time for that function. Afterwards, it's just in the scope of the function test() as a variable, but it is static so changing it changes it in all future calls to test() as well.