В реальном коде функция addChild
была бы реализована, если хранить объектный указатель Parent
в качестве указателя, не вступая во владение (т. Е. Позже он не удалит его на стороне C ++). Что делает py::keep_alive<1, 2>
, так это помещает ссылку из объекта Parent
на объект Child
, переданный в addChild
, таким образом связывая время жизни Child
с временем жизни Parent
.
Таким образом, если написать:
p = Parent()
p.addChild(Child())
, то без keep_alive
этот временный Child
объект выйдет из области видимости go (ref-count down to zero) на следующей строке. Вместо этого с keep_alive<1, 2>
происходит следующее (псевдокод):
p = Parent()
c = Child()
p.__keep_alive = c
p.addChild(c)
del c
Так что теперь, когда p
выходит из области видимости, его данные очищаются, в т.ч. ссылка __keep_alive
, в которой c
также очищается. Значение p
и «временный» дочерний элемент c
go выходят за рамки одновременно и не ранее.
РЕДАКТИРОВАТЬ : для keep_alive<0, 1>
- время жизни неявный this
привязан к возвращаемому значению. В тесте он используется только для проверки того, что эта политика может работать с возвратом None, но обычно при доступе к внутреннему элементу данных временного типа обычно имеет дело с промежуточными временными переменными в длинном выражении, например:
c = getCopyOfData().at(0).getField('f')
Проблема в том, что в C ++ время существования временных значений остается до конца оператора, поэтому вышеприведенное будет распространено в транслитерированном коде. Но в Python он заканчивается подсчетом повторений, равным 0. А вот, результат getCopyOfData()
исчезнет после завершения вызова at(0)
, оставив getField()
в удаленной памяти. Вместо этого с keep_alive<0, 1>
это будет (псевдокод):
d = getCopyOfData()
at0 = d.at(0)
at0.__keep_alive = d
del d
c = at0.getField('f')
c.__keep_alive = at0
del at0
Так что теперь скопированный контейнер данных d
не будет go вне области видимости, пока не будет сделана ссылка на доступное поле выходит за рамки.
Для keep_alive<1, 0>
время жизни возвращаемого значения привязано к неявному this
. Это полезно, если владение передается вызывающей стороне, а неявный this
сохраняет указатель, фактически откладывая управление памятью с C ++ до Python. Помните, что в pybind11 идентичность объекта сохраняется, поэтому любой вызов returnChildKeepAlive
, возвращающий тот же указатель, приведет к тому же Python объекту, а не к новому. Таким образом, в этом случае (псевдокод):
c = p.returnChildKeepAlive() # with c now owning the C++ object
p.__keep_alive = c
Если ссылка c
выходит первой из области видимости, p
все равно будет поддерживать ее работу, чтобы не застрять с висящим указателем. Если p
выходит первым из области видимости, c
не будет затронут, потому что он перешел во владение (то есть сторона C ++ не будет удалена). И если returnChildKeepAlive()
вызывается во второй раз, он вернет ссылку на ожидающий c
, а не новый прокси-сервер, что не повлияет на общее управление временем жизни.