Class instance reference count does not increase when holding one member attribute containing shared_pointers
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 18k
- Forks
- 2.3k
- Avg merge
- 5d 17h
- Merged PRs (30d)
- 10
Description
Hi there and thank you for maintaining this great piece of software.
Issue description
I have one class B that owns a std::vector<std::shared_ptr<A>> attribute named vec.
In short, on the Python side the instance of B is being deleted even though I still hold a reference to vec. If vec does not contains shared pointers but real objects, B is not being deleted.
From what I can see, this is due to B reference count not increasing while I am holding vec.
Reproducible example code
//c++ -Wall -shared -std=c++11 -fPIC -I pybind11/include -I /usr/include/python2.7/ test.cpp -o example.so
#include <vector>
#include <memory>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
using std::vector;
class A {
public:
A() {}
};
class B {
public:
B() {
vec.push_back(std::make_shared<A>());
}
~B() {
std::cout << "Destroying B" << std::endl;
}
const vector<std::shared_ptr<A>>& get_vector() const { return vec; }
vector<std::shared_ptr<A>> vec;
};
PYBIND11_MODULE(example, m_sub) {
py::class_<A, std::shared_ptr<A>>(m_sub, "A")
.def(py::init<>());
py::class_<B>(m_sub, "B")
.def(py::init<>())
.def_property_readonly("get_vector", &B::get_vector);
}
Python code:
import example as e
import sys
def foo(obj):
print(sys.getrefcount(obj))
a = obj.get_vector
print(sys.getrefcount(obj))
return a
t = foo(e.B())
print'end'
output:
3
3
Destroying B
end
This result in B being destroyed too early.
if now vec is of type std::vector<A> instead of std::vector<std::shared_ptr<A>>, it works as expected:
3
4
end
Destroying B
I don't know if what I am seeing is a bug or a feature... Any help about this would be appreciated.
Thanks a lot :)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the report with test.cpp and the shown Python snippet, then trace the .def_property_readonly("get_vector", &B::get_vector) binding and its lifetime handling. Compare the vector<shared_ptr<A>> and vector<A> cases; done means the retained vector no longer allows B to be destroyed prematurely.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- api, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100