Software & Apps

I love the global variable

I love and use the global variable

I know that speaking variables around the world will make your twitch. If you go to your Happy placeotherwise tie yourself in. I just don’t show you how I will use global variables, but I will also show you the enemy C ++.

Internal some_func() What do you think is using a world?

int logLevel;
static int prv_counter;
int counter() { return ++prv_counter; }
struct MyStruct { int debugID; MyStruct() { static int serial; debugID = ++serial; } };

void some_func() {
	auto originalLevel = logLevel;
	logLevel = moduleLogLevel;
	auto count = counter();
	MyStruct data;
	printf("What have ");
	//code
	printf("I done\n");
	logLevel = originalLevel;
}

Think a moment.

Tap to see what you want to think about.

  • The loglevel does not affect the program status. It is strictly changing the level of word.
  • counter () implemented by a global but some_func indirectly read or write it.
  • MyStruct Constructor uses a static int lived outside the scales and remains the amount of many calls.
  • Print can copy your string to a buffer. You may not be able to access its status, but many threads can write partial lines to affect the output.

I think of all over as using a global variable. Not only that but I think they are all good use.

Here is the bad use

int logLevel;
static int counter;
struct MyStruct { int id; MyStruct() { static int serial; id = ++serial; } };
void clear();
char*print(const char*sz);

void func2(const char*title) {
	clear();
	print("at ");
	auto sz = print(title);
	//use sz
}

void some_func() {
	logLevel = moduleLogLevel;
	auto id = ++counter;
	clear();
	auto tempSz = print("some_func ");
	auto idA = counter;
	auto idB = counter+1;
	counter += 2;
	func2("before some_func code");
	//more code
}

If this code is the same look, then no wonder why you don’t like the variables in the world. You don’t see good from evil.

  • logLevel not return the original value.
  • You use direct opponents, and not equal. The first ID takes the value after adding, while Ida / IDB takes the value before. Id == ia an easy to miss the mistake.
  • While not horrible, MyStruct It’s harder to try because you can’t reset the counter that generates the ID. In the first example, serial numbers for debugging goals that need to affect the test.

print a disaster. Unlike the first example, you can take access to the internal buffer. Do people expect Tempsz to participate or in this case written after calling a function? Is the case call case call before using print? (Who is Furc2), or incorrect because parent has cleared it? Why print returns to an unconditional? Was some used the use of the text partition cases outside the printing function? Will it be back so that you can shorten the text by writing null? All these potential problems make that print in a disaster.

Some rules for using globals

  1. It should be difficult or impossible to use incorrectly. For example, counter() Continues to add steadily.
  2. If you change the sight of the situation, return it.
  3. Do not return references or internal state points. Just because a function can be called from anywhere, does not mean that you need to directly change its status from anywhere. printf will not return a pointer. There is no way for you to keep up with its long buffer enough for the contents overwritten.
  4. Don’t make the test difficult. You can load a config file, there is only one instance of it, and read it. This technical can satisfy the above rules, but indeed you do a set of global available hard-coded values. It’s not just useless but people will write workarounds because of non-state repeat. The acquisition of many files used their own set of global variables so tweak behavior is easy to sync and make a high amount of bugs. The more difficult code is to try, it is more likely to have a person to write a workaround to avoid limits.

If you use threads, global and static variables should be local thread. If they have not been able to have discussions be part of sharing the data with threads and synchronization, which is different from the subject.

Let’s look at one of my favorite use

#include 
class INode {
public:
	virtual void process()=0;
	virtual ~INode() {};
};
void append_work(INode*task);

class NodeA : public INode { void process() override { } };
class NodeB : public INode { void process() override { append_work(new NodeA); } };
class NodeC : public INode { void process() override { 
		append_work(new NodeB); append_work(new NodeB);
	}
};

//Assume everything below is private
thread_local std::vectorworkList;

void append_work(INode*task) { workList.push_back(task); }

void process_nodes(INode*startNode) {
	//Save state so this function can be reentrant
	std::vectororiginal;
	original.swap(workList);
	std::vectorcurrent;
	workList.push_back(startNode);
	while(workList.size()) {
		current.clear();
		current.swap(workList);
		for(auto*node : current) {
			node->process();
			delete node; //You can avoid this with arenas
		}
	}
	workList.swap(original);
}

int main(int argc, const char*argv()) {
	process_nodes(new NodeC);
}

Let’s go to the checklist.

  1. ✅ It is difficult to use incorrect. Nodes have access only to Append_Wrow. They cannot clean the worklist or re-adjust nodes in this
  2. ✅ The original work list was restored.
  3. ✅ Worklist is not returned and empty inside it is returned.
  4. ✅ No hard attempt. You can use multiple threads or reorder tests just fine. The only thing that affects process_nodes/workList Did the node pass

Let’s look at a Bad Example

#include 

//Assuming we're using a language that forces us to use static variables
class Globals {
	static std::string personName, personEmail;
	static int personNumber; //technically wrong, supposedly there are numbers with leading 0's
public:
	static std::string getName()  { return personName; } //a copy is made here
	static std::string getEmail() { return personEmail; }//and here
	static int getNumber() { return personNumber; }

	static void setName(std::string name) { personName = name; }
	static void setEmail(std::string email) { personEmail = email; } 
	static void setNumber(int number) { personNumber = number; }
};

void second_func() {
	auto originalName = Globals::getName();
	auto originalNumber = Globals::getNumber();
	Globals::setName("New test");
	Globals::setNumber(321);
	//do work
	Globals::setName(originalName);
	Globals::setNumber(originalNumber);
}

void some_func() {
	Globals::setName("Test Name");
	Globals::setEmail("Test email");
	Globals::setNumber(12345);
	second_func();
}

int main(int argc, const char*argv()) {
	some_func();
}
//Ignore these, C++ requires this
std::string Globals::personName, Globals::personEmail;
int Globals::personNumber;

Let’s go to the checklist.

  1. ☢ It is very easy to use incorrect. Did you get the problem?
  2. ✅ We will change you and return the state
  3. ✅ Do not return the internal goods, ⚠️ but it sure makes the useless prints
  4. ✅ It’s not hard to try out, how to write the test error (first rule).

Breaking a rule is bad? Yes! A person who is not familiar with the codebase cannot notice the email used in the wrong name / number when entering “work” in the second function. Consider when you add a fourth attribute, do you want to add and return somewhere?

The third rule does not understand here. GETTERS / SETTERS it can read / write from anywhere. If that is not the functional status / file / module should be able to access direct variable directly. Since anyone can set the name / email / number they want, it is clearly not internal state. Copies don’t mean and get through. Here’s what I want to see

#include 

struct Person {
    std::string name, email;
    int number;
};
//Assuming we're using a language that forces us to use static variables
class Globals {
public:
    static Person*activePerson;
};

void second_func() {
    Person secondTest("New test", "", 321);
    
    auto originalPerson = Globals::activePerson;
    Globals::activePerson = &secondTest;
    //do work
    Globals::activePerson = originalPerson;
}

void some_func() {
    Person test("Test Name", "Test email", 12345);
    
    auto originalPerson = Globals::activePerson;
    Globals::activePerson = &test;
    second_func();
    Globals::activePerson = originalPerson;
}

int main(int argc, const char*argv()) {
    some_func();
}
//Ignore this, C++ requires this
Person*Globals::activePerson;

Now it’s impossible to have the wrong name / email / number used together because all fields are updated if you change something. You may notice the active person who is always bad when you enter the function so it is useless to take active person and return, that is not important. If some_func is a public function that can be called at any time. You don’t like the code to break because you make the mind you always overwrite a variable.

Many languages ​​have a defer feature that allows you to implement code when you leave the block or function. Using it allows restoring variables that are less wrong. C ++ has no delay, but it can be adapted to a macro and a sabboy. I’m writing PUSH(globalVar, newValue); And the macro + pretreatment manages the rest.

Some libraries have the context variable they want you to put the state. All of the above can be used. If you have changed status you most likely want to return it. If you want to avoid the globals by passing the arguments around, it should still be noted to return your update or you can have different arguments for each set of variables you mutate. If you do the last one and there are many calls on calls, you can do the code to change the account of how many lines / tasks you need to change.

Thoughts to end

World variables are more useful. If used correctly may your codebase feel less like spaghetti because of how many places you keep. People can remember variables as a new one and have bugs because an amount they need. We know we don’t have to use variables, I’m sure we’ll know that you don’t have to ignore global global revoked variables. If you do not use global variables, start a personal project. I know the globals that are most useful when walking in a tree, the next time you find yourself walking in a tree, try it to collect the stats or where you write your Output. Good luck and remember 4 rules.

2025-02-07 23:28:00

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button