Initializing static member just once throughout

Here I'm trying to initialize PersonFactory::ethnicSurnames just once for the entire run of the program:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <string>
#include <vector>
#include <array>

enum Country {India, China, France, NumCountries};  // plus many other countries
struct School {};  struct Mall {};  struct HockeyArena {};

struct PersonFactory {
	static std::array<std::vector<std::string>, NumCountries> ethnicSurnames;
	static int numberOfTimesInitialized;
	PersonFactory() {initializeEthnicNames();}
	PersonFactory(School*) {initializeEthnicNames();}
	PersonFactory(Mall*) {initializeEthnicNames();}
	PersonFactory(HockeyArena*) {initializeEthnicNames();}
private:
	void initializeEthnicNames() {
		std::cout << "PersonFactory::initializeEthnicNames() called" << std::endl;
		static const bool namesInitialized = (
			std::cout << "Carrying out the initialization..." << std::endl,
			numberOfTimesInitialized++,
			ethnicSurnames[India] = {"Ali", "Khan"},  // plus many more names
			ethnicSurnames[China] = {"Chung", "Lee"},
			ethnicSurnames[France] = {"LeMaitre, Bouchard"},
			// etc...
			true
		);
	}
};
std::array<std::vector<std::string>, NumCountries> PersonFactory::ethnicSurnames;
int PersonFactory::numberOfTimesInitialized = 0;

int main() {
	PersonFactory a, b, c(new School), d(new Mall), e(new HockeyArena);
	std::cout << "numberOfTimesInitialized = " << PersonFactory::numberOfTimesInitialized << std::endl;
	std::cin.get();
}

Output:
1
2
3
4
5
6
7
PersonFactory::initializeEthnicNames() called
Carrying out the initialization...
PersonFactory::initializeEthnicNames() called
PersonFactory::initializeEthnicNames() called
PersonFactory::initializeEthnicNames() called
PersonFactory::initializeEthnicNames() called
numberOfTimesInitialized = 1

As you can see, even though five PersonFactory objects were constructed, the ethnicNames initialization only occurred once, as desired. However, there are some issues with my method. First of all, the use of the comma operator is ugly in my opinion. But fashion statements aside, PersonFactory::initializeEthnicNames() is still called multiple times, which is not good, even though it correctly avoids reinitializing ethnicNames after the first call. Also, I now forever get the annoying compiler warnings that the bool namesInitialized is never used, which is true, thus wasting a small bit of memory. And finally, I cannot declare ethnicNames const now, and it is supposed to be const. Any better way to accomplish what I'm trying to do?

By the way, the reason why I don't initialize ethnic names outside the class as is normally done for static data members (and that would indeed allow me to declare it const) is because it would get messed up if I later change the order of the elements in enum Country. Hence actual lines of initializations I think are needed. And I do want ethnicSurnames inside PersonFactory, because I feel it really does belong there. Also, PersonFactory is not to be Singleton, because it has data members that depend on some parameters in its constructor (e.g. geographic location).
Last edited on
You could make initializeEthnicNames() a static function and instead of initializing ethnicSurnames directly it could return such an array so that the function could be used when ethnicSurnames is initialized. This allows ethnicSurnames to be declared as const and you don't have to call initializeEthnicNames() more than once.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <string>
#include <vector>
#include <array>

enum Country {India, China, France, NumCountries};  // plus many other countries
struct School {};  struct Mall {};  struct HockeyArena {};

struct PersonFactory {
	static const std::array<std::vector<std::string>, NumCountries> ethnicSurnames;
	static int numberOfTimesInitialized;
	PersonFactory() {}
	PersonFactory(School*) {}
	PersonFactory(Mall*) {}
	PersonFactory(HockeyArena*) {}
private:
	static std::array<std::vector<std::string>, NumCountries> initializeEthnicNames() {
		std::array<std::vector<std::string>, NumCountries> names;
		std::cout << "Carrying out the initialization..." << std::endl,
		numberOfTimesInitialized++,
		names[India] = {"Ali", "Khan"};  // plus many more names
		names[China] = {"Chung", "Lee"};
		names[France] = {"LeMaitre, Bouchard"};
		// etc...
		return names;
	}
};
const std::array<std::vector<std::string>, NumCountries> PersonFactory::ethnicSurnames = initializeEthnicNames();
int PersonFactory::numberOfTimesInitialized = 0;

int main() {
	PersonFactory a, b, c(new School), d(new Mall), e(new HockeyArena);
	std::cout << "numberOfTimesInitialized = " << PersonFactory::numberOfTimesInitialized << std::endl;
	std::cin.get();
}
Last edited on
First of all, the use of the comma operator is ugly in my opinion.
Yup. Pretty ugly.

PersonFactory::initializeEthnicNames() is still called multiple times, which is not good
Well, your choice: do you want to make a possibly unnecessary function call, or do you want to put if (!namesInitialized) in front of every function call?

thus wasting a small bit of memory
How is it wasted if you use it to alter control flow?

Any better way to accomplish what I'm trying to do?
Sure.
1
2
3
4
5
static bool namesInitialized = 0;
if (!namesInitialized){
    //...
    namesInitialized = 1;
}


it would get messed up if I later change the order of the elements in enum Country
I don't see how.
->I don't see how.

If PersonFactory::ethnicSurnames were initialized outside the class with Indian surnames first, Chinese surnames second, etc..., and then later I change enum Country to
enum Country {France, India, China, NumCountries};
then the French surnames returned by ethnicSurnames will be Indian, and so forth. So I will have to alter the outside initialization of PersonFactory::ethnicSurnames to correct that--a total mess.
But I think Peter came up with the simple solution that I missed. Or perhaps you had his idea in mind, in which case it won't affect it.
Last edited on
If PersonFactory::ethnicSurnames were initialized outside the class with Indian surnames first, Chinese surnames second, etc..., and then later I change enum Country to
enum Country {France, India, China, NumCountries};
then the French surnames returned by ethnicSurnames will be Indian, and so forth. So I will have to alter the outside initialization of PersonFactory::ethnicSurnames to correct that--a total mess.
Yeah, but you're not initializing ethnicSurnames as
1
2
3
ethnicSurnames[0] = {"Ali", "Khan"};  // plus many more names
ethnicSurnames[1] = {"Chung", "Lee"};
ethnicSurnames[2] = {"LeMaitre, Bouchard"};
You're using the enum values. As long as ethnicSurnames is always accessed using the enum, there's no need to change any code just because the order of the enum values changes.
What I meant was if it was initialized outside the class as:
1
2
3
4
5
const std::array<std::vector<std::string>, NumCountries> PersonFactory::ethnicSurnames = {
    {"Ali", "Khan"},
    {"Chung", "Lee"},
    {"LeMaitre, Bouchard"}
};

which was my original idea for initializing it. Then the mess I mentioned above would apply.
Last edited on
Topic archived. No new replies allowed.