шаблоны проектирования — порядок инициализации переменных / экземпляров c ++ в разных единицах перевода

Заранее спасибо.

Я видел эти коды в каком-то реальном проекте. Я просто упростил их, чтобы выразить свою проблему здесь. Базовый класс ставит этот указатель на вектор (VEC) в своем конструкторе. Используя этот трюк, мы можем управлять динамическим связыванием, чтобы вызывать метод производных классов снаружи (в основной функции). Ключевой момент — поместить определение вектора в Bash.h, а объявление в main.cpp.

Мой вопрос, выход не то, что я хочу. Почему vec инициализируется и используется в одной единице перевода (base.c, мы видим размер 1), затем в других единицах перевода (main.c, мы видим, что размер становится 0), инициализируется и очищается снова? Я хочу знать порядок инициализации по различным единицам перевода. Кажется, что сначала Derive :: dInstance, а затем vec, но почему?

Base.h

#ifndef BASE_H
#define BASE_h

#include<iostream>
#include<vector>
using namespace std;
class Base{
public:
Base();
virtual void speak();
};

#endif

Base.cpp

#include"Base.h"
vector<Base*> vec;
Base::Base() {
vec.push_back(this);
cout << "Base's constructor" << endl;
cout << "Base() vector size: " << vec.size() << endl;**
}

void Base::speak() {
cout << "I am Base" << endl;
}

Derive.h

#ifndef DERIVE_H
#define DERIVE_h
#include<iostream>
#include"Base.h"
class Derive: public Base {
public:
Derive();
virtual void speak();

static Derive dInstance;
};
#endif

Derive.cpp

#include "Derive.h"
// static member definition
Derive Derive::dInstance;

Derive::Derive() {
cout << "Derived's construtor" << endl;**
}
void Derive::speak() {
cout << "I am Derived" << endl;
}

main.cpp

#include<iostream>
#include"Base.h"
using namespace std;

extern vector<Base*> vec;
int main(int argc, char *argv[]) {
cout << "vector size: " << vec.size() << endl;

for(vector<Base*>::iterator iter = vec.begin(); iter != vec.begin(); iter++) {
(*iter)->speak();
}
}

Выход:

Конструктор базы
База () векторный размер: 1
Производный конструктор
main () векторный размер: 0

1

Решение

Это «static Порядок инициализации фиаско ».

Порядок инициализации между переводческие единицы из static (или глобальные) переменные не определены. Так что подумайте, что произойдет, если Derived.cpp файл инициализируется раньше Base.cppзатем вы добавляете к вектору, который не инициализирован (построен), что приводит к неопределенное поведение, затем вектор инициализируется.

1

Другие решения

Во-первых, не существует правила для порядка инициализации по различным единицам перевода.

И глобальная переменная и глобальная статическая переменная будут инициализированы перед основной функцией. Локальная статическая переменная, принадлежащая функции FuncA (), будет инициализирована при первом вызове FuncA ().

-1

По вопросам рекламы [email protected]