Chapter 6.1.1 of the book C++ Primer says the following:
Each local static object is initialized before the first time execution passes through the object’s definition. Local statics are not destroyed when a function ends; they are destroyed when the program terminates.
To check this, I ran the following code:
#include <iostream>
using std::clog;
using std::endl;
struct Bar {
Bar() {
clog << "constructing Num object" << endl;
}
int i = 0,
j = 0;
~Bar() {
clog << "destructing Num object" << endl;
}
};
void foo() {
clog << "foo() started" << endl;
static Bar b;
return;
}
int main() {
if (true) {
clog << "if-statement started" << endl;
foo();
}
clog << "if-statement exited" << endl;
return 0;
}
At this point in the book I haven't covered structs and classes yet, but it is my understanding that the function Bar() logs a message to the standard output when it gets created, and that b gets default initialized. If that is the case, then why does the output show that the object is constructed / initialized when control reaches static Bar b;, and not before it reaches this statement?
Output:
if-statement started
foo() started
constructing Num object
if-statement exited
destructing Num object
When are local static objects created?
As your book says: "before the first time execution passes through the object’s definition".
More precisely, the standard's wording is:
Dynamic initialization of a block-scope variable with static storage duration or thread storage duration is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization.
I think you're getting too hung up on the word "before". 🙂
Related
Object lifetime is usually tied to scope but when an object is created inside a function call things become a bit blurrier (at least to me). Check the code below:
#include <iostream>
#include <string>
using namespace std;
struct ins
{
ins() : _num(++num) { cout << "ctor " << _num << endl; }
~ins() { cout << "dtor " << _num << endl; }
int get() { return _num; }
static int num;
int _num;
};
int ins::num = 0;
ins geti() { return {}; }
void usei(int i) { cout << "using " << i << endl; }
int main()
{
usei(geti().get());
cout << endl;
usei(geti().get());
}
Output
ctor 1
using 1
dtor 1
ctor 2
using 2
dtor 2
Demo
Long story short, I want to know if there's a way to "calculate" the lifetime of objects in such cases. How would I know to what function each object is tied to? my current mental model of what's going on does not help me much.
After digging into cppreference, I found a section on object lifetime. Apparently my mental model on this was wrong.
Lifetime does not bind to functions in this case, but to expressions. My case pertains to temporary object lifetime, which is created by
returning a prvalue from a function
In that case the following rule applies:
All temporary objects are destroyed as the last step in evaluating the
full-expression that (lexically) contains the point where they were
created, and if multiple temporary objects were created, they are
destroyed in the order opposite to the order of creation. This is true
even if that evaluation ends in throwing an exception.
During some coding this morning I managed to enter and compile something akin to the following.
void a_function(void)
{
A_Class(std::string);
... //Other code continues
}
(names have been replaced to protect the identity of those classes involved)
What I had intended to have was a named instance A_Class an_instance(a_string); which I know would be in scope until the end of the function. What is the scope and lifetime of the A_Class created in this function?
I expect I could do something clever in the construction phase to make the lifetime almost anything I want. In this case the constructor makes a function call and a printf while the destructor does similar. Nothing invokes new, delete, malloc or anything of that sort.
Since C++98, a temporary lasts until the end of the full-expression, unless its lifetime is extended by binding to a reference.
The rules were different, as I recall, in ARM (the Annotated Reference Manual by Stroustrup and Ellis) C++.
It's not generally possible to figure out the standard's guarantees by just inspecting examples in a debugger or via trace statements, so the question has merit.
Only names have scope, so that concept is irrelevant here.
You're creating a temporary object.
Like all temporary objects, its lifetime lasts until the end of the full-expression where it was created, i.e until the ";" in this case, unless it's bound to a const reference variable.
The expression:
A_Class();
creates a temporary object of class A_Class. The temporary is destroyed after the evaluation of the full expression which lexicaly contains it -- in this case, the temporary will be destroyed immediately after its construction.
In an attempt to answer my own question,
Second Attempt
Updated test code now reads:
#include <iostream>
class Class_A
{
public:
Class_A(std::string a_string)
: saved_string(a_string)
{
std::cout << "Class_A Constructed:" << saved_string << std::endl;
}
~Class_A()
{
std::cout << "Class_A Deconstructed:" << saved_string << std::endl;
}
std::string saved_string;
};
class Class_B
{
public:
Class_B(std::string a_string)
: saved_string(a_string)
{
std::cout << "Class_B Constructed:" << saved_string << std::endl;
}
~Class_B()
{
std::cout << "Class_B Deconstructed:" << saved_string << std::endl;
}
std::string saved_string;
};
int main ()
{
std::cout << "Welcome to the lifetime test." << std::endl;
Class_A a_a("A");
Class_B a_b("B"); //Now I have to have () here too
std::cout << "Now for the interesting bit." << std::endl;
Class_A("a"); //Have to have the ()
Class_B("b");
std::cout << "Fin." << std::endl;
return 0;
}
Which when executed produces:
$ ./a.out
Welcome to the lifetime test.
Class_A Constructed:A
Class_B Constructed:B
Now for the interesting bit.
Class_A Constructed:a
Class_A Deconstructed:a
Class_B Constructed:b
Class_B Deconstructed:b
Fin.
Class_B Deconstructed:B
Class_A Deconstructed:A
So I can now see the lifetimes and I am compelled to use () or rather ("string") in the appropriate places. It is a little odd that a_a() is a function declaration inside a function in the First Attempt but `a_a_("A") is a constructor in the second. I was unaware that it was permitted to declare functions inside the definition of other functions but I suppose it make some sense for a few times when you might have some odd linkage going on in the background.
The lifetime of the unnamed temporary is only as long as the expression it is part of. Up until the ;.
First Attempt
I got as far as:
class Class_A
{
public:
Class_A()
{
std::cout << "Class_A Constructed" << std::endl;
}
~Class_A()
{
std::cout << "Class_A Deconstructed" << std::endl;
}
};
class Class_B
{
public:
Class_B()
{
std::cout << "Class_B Constructed" << std::endl;
}
~Class_B()
{
std::cout << "Class_B Deconstructed" << std::endl;
}
};
int main ()
{
std::cout << "Welcome to the lifetime test." << std::endl;
Class_A a_a();
Class_B a_b;
std::cout << "Now for the interesting bit." << std::endl;
Class_A(); //Have to have the ()
Class_B();
std::cout << "Fin." << std::endl;
return 0;
Which produces:
$ g++ main.cpp
$ ./a.out
Welcome to the lifetime test.
Class_B Constructed
Now for the interesting bit.
Class_A Constructed
Class_A Deconstructed
Class_B Constructed
Class_B Deconstructed
Fin.
Class_B Deconstructed
So I only have 1 Class_A constructed. Which is a little confusing as I would have expected a_a and a_b to have the same lifetimes. Now what have I done.
(update to follow I am sure)
It does seem to show that the calls to a constructor without a variable name only exist for the line/statement they are in (until the ;). This makes some sense when I think about functors, as pointed out by #douglas-o-moen
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();
What is the difference between declaring static variable inside a block and outside a block in a file? Eg, here, what is difference between static variables a,b,c,d? Can we declare a static variable that is accessible from all files of a program?
static int a;
void getVol(..)
{
static int b;
}
int main()
{
static int c;
while(condition)
{
static int d;
....
}
some code here;
return 0;
}
Ultimately, there is no difference. Ignoring (for the moment) static member functions, static means what it means -- but we see different parts of what it means under different conditions because some of what it means can also happen without the keyword.
When you use the static keyword, the object being defined always has:
static lifetime -- it exists for the entire life of the program.
local visibility -- the name is not visible outside the scope in which it is declared.
Both of these are true about a static variable whether defined inside or outside a block. One part or the other will happen by default, even if you don't use the static keyword, but if you use the keyword, you always get both.
static member functions are analogous, but since they're functions they don't exactly have lifetime -- all functions have static lifetime. A static member function has local visibility (i.e., its name is visible only with its class) and something sort of like "static lifetime" -- the function isn't bound to an instance of the class.
For those who care about the specific time at which a block-level static variable is initialized, the gory details are as follows (§6.7/4):
The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered.
An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization.
So, the variable will be zero-initialized very early in the startup of the program. Then, if other initialization has been specified, that will happen no later than when execution passes through the initialization (but could happen earlier than that). Note, however, the difference between constant initialization and other initialization. Just for example, consider something like this:
int g() { return 2; }
int f() {
goto bypass;
static int x = 1;
static int y = g();
bypass:
std::cout << x << "\n" << y;
}
Here, x is constant initialized, but y is not. Since x is constant initialized, it is initialized upon entry to the block, so when we print out its value, we should get 1. y, however, is not constant initialized, and the goto means that execution never flows through its initialization -- therefore, it will retain the 0 that it was initialized with before any other initialization took place, so (with a properly functioning compiler) the output will be:
1
0
Static variable inside a block(local static variable) -
It is not visible outside the block/function
It's value retains in function calls as it is static
Static variable outside a block(Global static variable) -
It's scope is the entire file(like a in your program)
It's value retains between function calls as it is static.
static int a;
means the variable a is a file scope variable, i.e, it can't be seen from other files.
void getVol(..)
{
static int b;
}
means the local variable b has a life cycle that goes from the program starts to the program ends, i.e, you can assign it some value, while on the next call of the function, it remembers that value.
c and d are similar to b.
The following worked for me:
/*
* How to create an object on the stack.
* Also make sure that only 5 objects are created for the class
*/
#include <iostream>
using namespace std;
class User {
private:
int id;
static int counter;
static bool isOk;
public:
User();
~User() {}
int getId() { return id; }
static int getCounter() { return counter; }
static bool getStatus() { return isOk; }
static void resetOk() { isOk = false; }
static void setOk() { isOk = true; }
};
User::User() {
if(counter == 5) {
cout << "Not allowed to create more than 5 objects" << endl;
resetOk();
return;
}
counter++;
id = counter;
setOk();
}
int User::counter = 0;
bool User::isOk = false;
int main()
{
// Create objects on stack
User user1;
(User::getStatus()) ? cout << "user1 id: " << user1.getId() << endl :
cout << "Object Construction Failed" << endl;
User user2;
(User::getStatus()) ? cout << "user2 id: " << user2.getId() << endl :
cout << "Object Construction Failed" << endl;
User user3;
(User::getStatus()) ? cout << "user3 id: " << user3.getId() << endl :
cout << "Object Construction Failed" << endl;
User user4;
(User::getStatus()) ? cout << "user4 id: " << user4.getId() << endl :
cout << "Object Construction Failed" << endl;
User user5;
(User::getStatus()) ? cout << "user5 id: " << user5.getId() << endl :
cout << "Object Construction Failed" << endl;
User user6;
(User::getStatus()) ? cout << "user6 id: " << user6.getId() << endl :
cout << "Object Construction Failed" << endl;
User user7;
(User::getStatus()) ? cout << "user7 id: " << user7.getId() << endl :
cout << "Object Construction Failed" << endl;
return 0;
}
static int a;//file scope variable
void getVol()
{
static int b;//fixed duration
}
File scoped variables act exactly like global variables, except their use is restricted to the file in which they are declared (which means you can not extern them to other files).
A fixed duration variable is one that retains it’s value even after the scope in which it has been created has been exited! Fixed duration variables are only created (and initialized) once, and then they are persisted throughout the life of the program.
Check this link:http://www.learncpp.com/cpp-tutorial/43-file-scope-and-the-static-keyword/
Using the static keyword in block scope is exactly like a global variable with respect to where it is stored, however the difference is that it is only accessible within the block scope that it was declared. Recall that as you nest blocks the inner-most block takes precedence when referencing an identifier -- which the same applies to static variables.
Consider the following snippet of code to illustrate my response:
#include <stdio.h>
void f1( void ) {
static int a = 10;
{
static int a = 9;
printf( "inner a = %d\n", a );
}
printf( "outer a = %d\n", a );
}
int main( void ) {
for ( int i = 0; i < 10; i++ ) {
printf( "Calling the function f1.\n" );
f1();
}
return 0;
}
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.