In depth study of C + + - 21 ~ 23 static

In depth study of C + + - 21 ~ 23 static

Static has two meanings in C + +, including static outside class and structure and static inside class and structure

21. Static of classes and structures

Static outside the class and structure means that the symbol you declare as static is only linked inside the current file, and it is only visible to the translation unit where it is located. For the translation unit, please see the in-depth study of C + + - 6~7 compiler and linker

Create a new source file named CStatic CPP, in main CPP and CStatic CPP defines a variable and a function at the same time, and the compiler will report an error multiple definition of XXX in the linking stage, because this variable / function has been defined in another compilation unit. So we can't have two global variables / functions with the same name. One way to modify it is to use the extern keyword, which means that it will look for the variable / function in the external translation unit. We put main Add static to the definition in CPP and compile again without error.

/*CStatic.cpp*/
int Variable = 5;
void Function()
{
	std::cout << "Function in CStatic" << std::endl;
}

/*main.cpp*/
//int Variable = 5; //multiple definition of Variable
//void Function() //multiple definition of `Function()'
//{
//	std::cout << "Variable" << std::endl;
//}
extern int Variable;
extern void Function(); //All functions are extern by default. You can also compile by deleting extern here
int main()
{
	Function();
	std::cout << Variable << std::endl;
}

Another solution is to use the static keyword. Static means that this variable / function will only be linked within this translation unit. This is a bit like defining a private variable / function in a class. All other translation units cannot see this variable / function. The linker will not see this variable / function under the global scope. Put CStatic The variables and functions in CPP are changed to static, and the compilation will report errors, because they are not visible in main and cannot be found across translation units. Set main The variables and functions in CPP are modified to be global. At this time, the compilation passes, and the output is the variable values and functions defined in main.

/*CStatic.cpp*/
static int Variable = 5;
static void Function()
{
	std::cout << "Function in CStatic" << std::endl;
}

/*main.cpp*/
//extern int Variable; //undefined reference to `Function()'
//extern void Function(); //undefined reference to `Variable'
int Variable = 10;
void Function()
{
	std::cout << "Function in main" << std::endl;
}
int main()
{
	Function();
	std::cout << Variable << std::endl;
}

Using static outside of classes and structures means that when you declare static functions and static variables, it will only be "seen" in the C + + file it is declared. If you declare a static variable in a header file and include the header file in two different C + + files, it is equivalent to declaring that variable as a static variable in both translation units. (when the header file is included, the compiler will copy the contents of all header files to the C + + file)

Why use static? An analogy can be made to why private is used in a class. When you don't need variables to be global variables, use static variables as much as possible. Because once something is declared under the global scope, the compiler will link across the compilation unit. This variable can be used anywhere, which may lead to some serious bug s.

To sum up, mark functions or variables as static as possible, unless you really need them to link across translation units.

22. Static in classes and structures

The static variable defined inside the class and structure has only one instance in all instances of the class, which means that the variable will actually share memory with all instances of the class. For static functions, no instance is passed to a static function.

Let's take the structure as an example (the same is true for classes, just because the structure is public by default)

struct Entity
{
	int num;
	void Print()
	{
		std::cout << num << std::endl;
	}
};

int main()
{
	Entity e1;
	e1.num = 2;

	Entity e2;
	e2.num = 5;

	e1.Print();
	e2.Print();
}

Obviously, this will output 2 and 5. If x and Y in the structure become static, it will report an error undefined reference to 'Entity::num', because X and y need to be defined somewhere, plus int Entity::num;, The procedure is modified to:

struct Entity
{
	static int num;
	void Print()
	{
		std::cout << num << std::endl;
	}
};

int Entity::num;

int main()
{
	Entity e1;
	e1.num = 2;

	Entity e2;
	e2.num = 5;

	e1.Print();
	e2.Print();
}

At this time, the operation will output 5 and 5 This is because the num variable has only one instance in all instances of the Entity class, which means E1 Num and E2 Num points to the same memory, so E1 Num and E2 It makes no sense to write num like this. It can be written directly as Entity::num = 5. It's like creating a variable in a namespace called Entity. They don't actually belong to the class, but they can be private or public, so they are still part of the class. But in terms of application, they are actually the same as in namespace.

Static methods are the same as static variables. If you change Print to static, you also need to use Entity::Print();

However, static methods cannot access non static variables. Change num to non static variables and keep Print as static methods. At this time, the compilation will report an error: invalid use of member 'Entity::num' in static member function because the static method has no class instance. Each non static method will always get an instance of the current class as a parameter, which we can't see. It works through hidden parameters at the bottom, while static methods won't get that hidden parameter. The static methods in the class are actually like this when they are compiled outside the class. An instance parameter is actually uploaded, so that no error will be reported:

struct Entity
{
	int num;
};
static void Print(Entity e)
{
	std::cout << e.num << std::endl;
}

int main()
{
	Entity e;
	e.num = 5;
	Print(e);
}

To sum up, when you need to use variables across classes, static variables in classes will come in handy. So isn't it the same to create a global variable or a static variable? NO! If you have a message and want to share data between all instances, it makes sense to put the message variable in the class because it is logically related to the class. To organize your code, you'd better create a static variable in your class instead of scribbling global or static variables everywhere.

23. Local static

Local static allows us to create a variable whose lifetime is basically equivalent to the lifetime of the whole program, but the scope is limited to this domain. Let's look at a program:

void Function()
{
	int i = 0;
	i++;
	std::cout << i << std::endl;
}
int main()
{
	Function();
	Function();
	Function();
	Function();
	Function();
}

Obviously, the output is 11111. If you want to increase i every time to achieve output 12345, your first reaction may be to change i to a global variable. But doing so will make this variable accessible to everyone. If you want to avoid this problem, you can declare i as static under the local scope. In this way, the program can also output 12345, which has the same effect as the global variable, but at this time, i is only a local variable under the scope of the function.

The main function of using local static is to make the code cleaner. Let's take another example. Create a singleton class (a singleton class is a class with only one instance). If you do not use the static local scope to create a singleton class, you need to create a static singleton instance, which may be a pointer and return a reference, that is, the created instance:

class Singleton
{
private:
	static Singleton* s_Instance;
public:
	static Singleton& Get()
	{
		return *s_Instance;
	};

	void Hello()
	{
		std::cout << "Hello" << std::endl;
	}
};

Singleton* Singleton::s_Instance = nullptr;

int main()
{
	Singleton::Get().Hello();
}

If you use local static to create, the code will become much cleaner:

class Singleton
{
public:
	static Singleton& Get()
	{
		static Singleton instance;
		return instance;
	};
	void Hello()
	{
		std::cout << "Hello" << std::endl;
	}
};

int main()
{
	Singleton::Get().Hello();
}

If there is no static in this code, instance will be destroyed when the code runs to the right curly bracket of the function, that is, the scope of the function ends. By adding static, its life cycle is extended forever. When calling Get for the first time, it will actually construct a singleton instance, and then it will only return the existing instance.

Tags: C++ Ubuntu Visual Studio ROS2

Posted by Abz on Mon, 14 Mar 2022 12:08:57 +1030