взять этот код
#include<boost/python>
namespace bp = boost::python;
bp::list py_points; //initial list
other_class* C; // this class have a bp::list attribute called py_list
// ... some code ....
// in this part C.py_list.ptr() is 0x0
other_class->py_list = py_list; // problem here!!
проблема заключается в том, что оператор "="
в отладчике в файле object_core.hpp, это файл основного файла python
inline api::object_base& api::object_base::operator=(api::object_base const& rhs)
{
Py_INCREF(rhs.m_ptr);
Py_DECREF(this->m_ptr); // in this line the program fail
this->m_ptr = rhs.m_ptr;
return *this;
}
каков правильный способ использования оператора "="
отредактированный
проблема заключается в стеке, если указатель other_class-> py_list имеет значение null (или None, потому что конструктор класса не вызывается), программа не может вызывать función Py_DECREF (не существует ссылок до указателя NULL)
проблема заключается в исправлении вызова конструктора
other_class* C = new othe_class(); // fixed!!
Проблема заключается не в операторе присваивания, проблема в том, что внутренний указатель py_list
PyObject
является nullptr
. В большинстве случаев указатель не должен быть нулевым. С точки зрения Python он должен по крайней мере управлять ссылкой на объект Python None
, как это сделано по умолчанию построенным boost::python::object
. Конструктор по умолчанию для boost::python::list
создает новый пустой список. Следовательно, источник проблемы, вероятно, находится в конструкторе other_class
или блоке "некоторый код".
Чтобы уточнить вопрос, поставленный в заголовке, создание справочного или копирующего списка в Boost.Python такое же, как в Python:
Оператор присваивания создаст ссылку на список.
>>> a = ['spam']
>>> b = a
>>> b
['spam']
>>> a is b
True
Можно нарезать список, чтобы создать мелкую копию.
>>> a = ['spam']
>>> b = a[:]
>>> b
['spam']
>>> a is b
False
Вот полный пример с эквивалентным кодом Python, аннотированным в комментариях.
#include <iostream>
#include <boost/python.hpp>
/// @brief Mockup class.
struct other_class
{
boost::python::list py_list;
};
/// @brief Helper function to print object id and its string representation.
std::string to_string(boost::python::object& o)
{
std::stringstream stream;
stream << o.ptr() << " = "
<< boost::python::extract<std::string>(o.attr("__str__")())();
return stream.str();
}
int main()
{
using std::cout;
using std::endl;
namespace python = boost::python;
Py_Initialize();
try
{
python::object object; // object = None
cout << to_string(object) << "\n" // print object
<< " is none check: " << object.is_none() // print object is None
<< endl;
// Create other_class and populate its list.
other_class* c = new other_class(); // py_list = []
cout << "c->py_list: " << to_string(c->py_list) // print py_list
<< endl;
c->py_list.append("spam"); // py_list.append("spam")
cout << "c->py_list: " << to_string(c->py_list) // print py_list
<< endl;
// Have list1 reference c->py_list.
python::list list1; // list1 = []
cout << "list1: " << to_string(list1) << "\n" // print list1
<< "assign py_list to list1" << endl;
list1 = c->py_list; // list1 = py_list
cout << "list1: " << to_string(list1) << endl; // print list1
// Modify list1 and observe effects on pylist.
cout << "modify list1" << endl;
list1.append(42); // list1.append(42)
cout << "c->py_list: " << to_string(c->py_list) // print py_list
<< endl;
// Shallow-copy list1.
cout << "copying list1 into list2" << endl;
python::list list2(
list1.slice(python::_, python::_)); // list2 = list1[:]
list2.append("eggs"); // list2.append("eggs")
cout << "list2: " << to_string(list2) << "\n" // print list2
<< "list1: " << to_string(list1) << endl; // print list1
delete c;
}
catch (python::error_already_set&)
{
PyErr_Print();
}
}
Вывод:
0x804e1ac = None
is none check: 1
c->py_list: 0xb707024c = []
c->py_list: 0xb707024c = ['spam']
list1: 0xb70da98c = []
assign py_list to list1
list1: 0xb707024c = ['spam']
modify list1
c->py_list: 0xb707024c = ['spam', 42]
copying list1 into list2
list2: 0xb707cb0c = ['spam', 42, 'eggs']
list1: 0xb707024c = ['spam', 42]
Несколько замечаний в выводе:
boost::python::list
objects управляют ссылкой на пустой список. 0x804e1ac
- None
, и ни один из внутренних указателей PyObject
объекта списка не ссылается на него.list1 = py_list
назначение вызывает list1
управлять ссылку на тот же список, управляемый py_list
. Это проявляется в выходе по list1
первоначально управлениям ссылкой на 0xb70da98c
, но после присваивания, он управляет ссылкой на 0xb707024c
. С list1
и py_list
управления тем же списком, изменение списка с помощью одной ручки можно наблюдать в другой ручке.PyObject
внутренняя точка для list2
управляет другой ссылки (0xb707cb0c
), чем list1
указатель (0xb707024c
).