Способ думать об этом - «думать как компилятор».
Представьте, что вы пишете компилятор. И вы видите такой код.
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
Когда вы компилируете файл .cc (помните, что .cc, а не .h - это единица компиляции), вам нужно выделить пространство для объекта A
. Итак, хорошо, сколько пространства тогда? Достаточно хранить B
! Каков размер B
? Достаточно хранить A
!
Очевидно, что круговая ссылка, которую вы должны сломать.
Вы можете ее разбить, разрешив компилятору зарезервировать столько места, сколько он знает о указателях и ссылках на передний план, для например, всегда будет 32 или 64 бита (в зависимости от архитектуры), и поэтому, если вы замените (или один) указателем или ссылкой, все будет замечательно. Скажем, мы заменим в A
:
// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
Теперь все лучше. В некотором роде. main()
все еще говорит:
// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include
, для всех экстентов и целей (если вы выберете препроцессор) просто копирует файл в .cc. Так что, .cc выглядит так:
// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
Вы можете понять, почему компилятор не может с этим справиться - он понятия не имеет, что B
- он даже не видел символ раньше .
Итак, давайте расскажем компилятору о B
. Это известно как декларация вперед и обсуждается далее в этом ответе .
// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
Это работает . Это не отлично . Но на этом этапе у вас должно быть понимание проблемы с круговой ссылкой и что мы сделали, чтобы «исправить» ее, хотя исправление плохо.
Причина, по которой это исправление плохо, заключается в следующем: f17] должны объявить B
, прежде чем они смогут его использовать, и получите ужасную ошибку #include
. Итак, давайте переместим декларацию в себя.
// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
И в Bh на данный момент вы можете просто #include "A.h"
прямо.
// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
HTH.
Возможно, вам захочется посмотреть на этот вопрос SQL-загрузчик связей Alchemy оставляет блокировку на таблице?
Что вам нужно сделать, это подкласс flask.ext.sqlalchemy.SQLAlchemy
и переопределить метод apply_driver_hacks
для прохождения через дополнительный аргумент ключевого слова isolation_level='READ <some level>'
:
from flask.ext.sqlalchemy import SQLAlchemy
class UnLockedAlchemy(SQLAlchemy):
def apply_driver_hacks(self, app, info, options):
if not "isolation_level" in options:
options["isolation_level"] = "READ COMMITTED" # For example
return super(UnLockedAlchemy, self).apply_driver_hacks(app, info, options)