使用cppyy处理右值指针与std::map时的问题求助
Cppyy中std::map结合右值引用/std::move的问题解决
问题描述
问题1:std::string存入std::map时触发TypeError
执行以下代码尝试将std::move处理后的std::string存入std::map<std::string, std::string>:
test_map = Cpp.std.map[Cpp.std.string, Cpp.std.string]() test_string = Cpp.std.string("value") test_map["key"] = Cpp.std.move(test_string) print(test_map["key"])
报错信息:
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[34], line 3 1 test_map = Cpp.std.map[Cpp.std.string, Cpp.std.string]() 2 test_string = Cpp.std.string("value") ----> 3 test_map["key"] = Cpp.std.move(test_string) 4 print(test_map["key"]) TypeError: none of the 2 overloaded methods succeeded. Full details: std::string& std::map<std::string,std::string>::operator[](std::map<std::string,std::string>::key_type&& __k) => logic_error: basic_string::_M_construct null not valid std::string& std::map<std::string,std::string>::operator[](const std::map<std::string,std::string>::key_type& __k) => logic_error: basic_string::_M_construct null not valid
问题2:自定义模板类存入std::map时出现编译错误与TypeError
自定义模板类代码:
import cppyy import cppyy.gbl as Cpp cppyy.cppdef(r"""\ template<typename T> class MyClass { public: MyClass(T t) : m_data(t) {} T m_data; }; """)
执行代码尝试存入std::move处理后的对象:
test_map = Cpp.std.map[Cpp.std.string, Cpp.MyClass['double']]() myClass = Cpp.MyClass['double'](5.0) test_map["key"] = Cpp.std.move(myClass) print(test_map["key"])
报错信息:
input_line_50:6:86: error: no member named 'operator[]' in 'std::map<std::__cxx11::basic_string<char>, MyClass<double>, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, MyClass<double> > > >' new (ret) (MyClass<double>*) (&((std::map<std::string,MyClass<double> >*)obj)->operator[]((std::string&&)*(std::string*)args[0])); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ input_line_50:10:55: error: no member named 'operator[]' in 'std::map<std::__cxx11::basic_string<char>, MyClass<double>, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, MyClass<double> > > >' ((std::map<std::string,MyClass<double> >*)obj)->operator[]((std::string&&)*(std::string*)args[0]); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ input_line_51:6:86: error: no member named 'operator[]' in 'std::map<std::__cxx11::basic_string<char>, MyClass<double>, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, MyClass<double> > > >' new (ret) (MyClass<double>*) (&((std::map<std::string,MyClass<double> >*)obj)->operator[]((const std::string&)*(const std::string*)args[0])); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ input_line_51:10:55: error: no member named 'operator[]' in 'std::map<std::__cxx11::basic_string<char>, MyClass<double>, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, MyClass<double> > > >' ((std::map<std::string,MyClass<double> >*)obj)->operator[]((const std::string&)*(const std::string*)args[0]); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ --------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[45], line 3 1 test_map = Cpp.std.map[Cpp.std.string, Cpp.MyClass['double']]() 2 myClass = Cpp.MyClass['double'](5.0) ----> 3 test_map["key"] = Cpp.std.move(myClass) 4 print(test_map["key"]) TypeError: none of the 2 overloaded methods succeeded. Full details: MyClass<double>& std::map<std::string,MyClass<double> >::operator[](std::map<std::string,MyClass<double> >::key_type&& __k) => ReferenceError: none of the 2 overloaded methods succeeded. Full details: attempt to access a null-pointer attempt to access a null-pointer MyClass<double>& std::map<std::string,MyClass<double> >::operator[](const std::map<std::string,MyClass<double> >::key_type& __k) => TypeError: none of the 2 overloaded methods succeeded. Full details: MyClass<double>& MyClass<double>::operator=(MyClass<double>&&) => ValueError: could not convert argument 1 (object is not an rvalue) attempt to access a null-pointer
解决方案
问题1修复:避免使用operator[],改用emplace/insert
std::map::operator[]的逻辑是:若key不存在则默认构造一个value,再返回引用供赋值。cppyy在处理这个流程结合右值引用时会触发构造错误。直接用emplace原地构造键值对,或insert插入移动后的pair即可解决:
test_map = Cpp.std.map[Cpp.std.string, Cpp.std.string]() test_string = Cpp.std.string("value") # 方案1:用emplace直接构造,自动处理右值 test_map.emplace(Cpp.std.move(Cpp.std.string("key")), Cpp.std.move(test_string)) # 方案2:用insert插入pair # test_map.insert({Cpp.std.string("key"), Cpp.std.move(test_string)}) # 用at()访问元素,避免operator[]的默认构造逻辑 print(test_map.at(Cpp.std.string("key")))
问题2修复:补充类的必要构造/赋值函数,或跳过operator[]
核心原因
std::map::operator[]要求value类型必须支持默认构造,你的MyClass没有默认构造函数,导致cppyy无法找到对应的operator[]重载,触发编译错误。- cppyy处理右值赋值时,需要类有明确的移动赋值运算符。
修复方案
方案A:补充类的默认构造和移动赋值(兼容operator[])
修改自定义类代码:
import cppyy import cppyy.gbl as Cpp cppyy.cppdef(r"""\ template<typename T> class MyClass { public: MyClass() : m_data(T{}) {} // 添加默认构造函数 MyClass(T t) : m_data(t) {} // 添加移动赋值运算符 MyClass& operator=(MyClass&& other) noexcept { if (this != &other) { m_data = std::move(other.m_data); } return *this; } T m_data; }; """)
之后可以使用operator[],但更推荐用emplace:
test_map = Cpp.std.map[Cpp.std.string, Cpp.MyClass['double']]() myClass = Cpp.MyClass['double'](5.0) test_map.emplace(Cpp.std.string("key"), Cpp.std.move(myClass)) print(test_map.at(Cpp.std.string("key")).m_data)
方案B:跳过operator[],直接用emplace/insert(无需修改类)
如果不想修改MyClass,直接用emplace插入键值对,它不需要value支持默认构造:
test_map = Cpp.std.map[Cpp.std.string, Cpp.MyClass['double']]() myClass = Cpp.MyClass['double'](5.0) test_map.emplace(Cpp.std.string("key"), Cpp.std.move(myClass)) print(test_map.at(Cpp.std.string("key")).m_data)
内容的提问来源于stack exchange,提问作者shouriha
相关产品推荐
相关产品推荐

