初始化 cppyy 中对象指针的 std::map

Initializing std::map of pointers of objects in cppyy

提问人:shouriha 提问时间:6/15/2023 最后编辑:shouriha 更新时间:6/15/2023 访问量:70

问:

我正在尝试从 cppyy 初始化从字符串到唯一指针的映射。我可以毫无问题地制作指针向量,但是当我制作地图时,我收到了 cppyy 的一些投诉。这是我的课程:

import cppyy
import cppyy.gbl as Cpp

cppyy.cppdef(r"""\

#include <cmath>
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <memory>


class Zoo
{
  // generic Zoo interface
  public: 
      Zoo() = default; 
      virtual ~Zoo() = default;
      
      virtual void printAnimals() = 0; 
};

template<typename TAnimalType> class SpecificZoo:
  public Zoo
{
  public: 
      virtual std::vector<TAnimalType> getAnimals() = 0;
};

class Bird{
};

class Fish{
};

class Aquarium: public SpecificZoo<Fish>{
  public: 
      void printAnimals() override {
          std::cout << "fish"; 
      }
      std::vector<Fish> getAnimals() override {
          return {}; 
      }
};

class Aviary: public SpecificZoo<Bird>{
  public: 
      void printAnimals() override {
          std::cout << "Birds"; 
      }
      std::vector<Bird> getAnimals() override {
          return {}; 
      }
};

int main(){
    std::vector<std::unique_ptr<Zoo>> zoos{}; 
    auto aquarium = std::make_unique<Aquarium>();
    zoos.push_back(std::move(aquarium));
    auto aviary = std::make_unique<Aviary>();
    zoos.push_back(std::move(aviary));
    
    std::cout << zoos.size() << std::endl;
    std::cout << "Done making zoo vector" << std::endl; 

    std::map<std::string, std::unique_ptr<Zoo>> zooMap{}; 
    auto aquarium2 = std::make_unique<Aquarium>();
    auto aviary2 = std::make_unique<Aviary>();
    
    zooMap.emplace("aquarium", std::move(aquarium2));
    zooMap.emplace("aviary", std::move(aviary2));

    std::cout << zooMap.size() << std::endl;
    std::cout << "Done making zoo map" << std::endl; 
}

""")

要制作指针向量,我可以做:

zoos = Cpp.std.vector[Cpp.std.unique_ptr[Cpp.Zoo]]()
print("Created zoos")
aquarium = Cpp.Aquarium()
aviary = Cpp.Aviary()

zoos.push_back(Cpp.std.move(aquarium))
zoos.push_back(Cpp.std.move(aviary))

但是,为了制作地图,我尝试了:

zooDict = Cpp.std.map[Cpp.std.string, Cpp.std.unique_ptr[Cpp.Zoo]]()
aquarium2 = Cpp.std.make_unique[Cpp.Aquarium]()
aviary2 = Cpp.std.make_unique[Cpp.Aviary]()

print(aquarium2)
zooDict.emplace('aquarium', Cpp.std.move(aquarium2))
zooDict.emplace('aviary', Cpp.std.move(aviary2))

print(f'Zoo dict created? {zooDict}')

for key, val in zooDict:
    print(key, val)

崩溃并显示以下错误:

IncrementalExecutor::executeFunction: symbol '_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10unique_ptrI3ZooSt14default_deleteISB_EEEEE9constructISF_JS8_8AquariumEEEvPT_DpOT0_' unresolved while linking symbol '__cf_15'!
You are probably missing the definition of void __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > > > >::construct<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Aquarium>(std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, Aquarium&&)
Maybe you need to load the corresponding shared library?

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[5], line 6
      3 aviary2 = Cpp.std.make_unique[Cpp.Aviary]()
      5 print(aquarium2)
----> 6 zooDict.emplace('aquarium', Cpp.std.move(aquarium2))
      7 zooDict.emplace('aviary', Cpp.std.move(aviary2))
      9 print(f'Zoo dict created? {zooDict}')

ValueError: Template method resolution failed:
  std::pair<std::_Rb_tree_iterator<std::pair<const std::string,std::unique_ptr<Zoo,std::default_delete<Zoo> > > >,bool> std::map<std::string,std::unique_ptr<Zoo,std::default_delete<Zoo> > >::emplace(std::string&& __args, Aquarium&& __args) =>
    ValueError: nullptr result where temporary expected

我也试过不创建:unique_ptr

zooDict = Cpp.std.map[Cpp.std.string, Cpp.std.unique_ptr[Cpp.Zoo]]()
aquarium2 = Cpp.Aquarium()
aviary2 = Cpp.Aviary()

zooDict.emplace('aquarium', Cpp.std.move(aquarium2))
zooDict.emplace('aviary', Cpp.std.move(aviary2))

print(f'Zoo dict created? {zooDict}')

for key, val in zooDict:
    print(key, val)

崩溃并显示以下错误:

IncrementalExecutor::executeFunction: symbol '_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10unique_ptrI3ZooSt14default_deleteISB_EEEEE9constructISF_JS8_8AquariumEEEvPT_DpOT0_' unresolved while linking symbol '__cf_12'!
You are probably missing the definition of void __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > > > >::construct<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Aquarium>(std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, Aquarium&&)
Maybe you need to load the corresponding shared library?

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[5], line 5
      2 aquarium2 = Cpp.Aquarium()
      3 aviary2 = Cpp.Aviary()
----> 5 zooDict.emplace('aquarium', Cpp.std.move(aquarium2))
      6 zooDict.emplace('aviary', Cpp.std.move(aviary2))
      8 print(f'Zoo dict created? {zooDict}')

ValueError: Template method resolution failed:
  std::pair<std::_Rb_tree_iterator<std::pair<const std::string,std::unique_ptr<Zoo,std::default_delete<Zoo> > > >,bool> std::map<std::string,std::unique_ptr<Zoo,std::default_delete<Zoo> > >::emplace(std::string&& __args, Aquarium&& __args) =>
    ValueError: nullptr result where temporary expected

最后,我尝试不移动对象,不制作指针,这不会崩溃,但它仍然会产生警告消息

zooDict = Cpp.std.map[Cpp.std.string, Cpp.std.unique_ptr[Cpp.Zoo]]()
aquarium2 = Cpp.Aquarium()
aviary2 = Cpp.Aviary()

zooDict.emplace('aquarium', aquarium2)
zooDict.emplace('aviary', aviary2) 

print(f'Zoo dict created? {zooDict}')

for key, val in zooDict:
    print(key, val)
IncrementalExecutor::executeFunction: symbol '_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10unique_ptrI3ZooSt14default_deleteISB_EEEEE9constructISF_JS8_R8AquariumEEEvPT_DpOT0_' unresolved while linking symbol '__cf_12'!
You are probably missing the definition of void __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > > > >::construct<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Aquarium&>(std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, Aquarium&)
Maybe you need to load the corresponding shared library?

我应该做些什么来不收到此错误消息吗?我是否正确创建了这个对象?


编辑以回应@273k的回答。这样做几乎可以奏效,我在单元格第一次运行时收到警告,但如果我再次运行它,警告就会消失。(python 的字符串会自动转换为 Cpp.std.string,但即使我明确这样做,警告仍然存在。

zooDict = Cpp.std.map[Cpp.std.string, Cpp.std.unique_ptr[Cpp.Zoo]]()
aquarium2 = Cpp.Aquarium()
aviary2 = Cpp.Aviary()

zooDict.emplace(Cpp.std.make_pair[Cpp.std.string, Cpp.std.unique_ptr[Cpp.Zoo]]('aquarium', Cpp.std.move(aquarium2)))
zooDict.emplace(Cpp.std.make_pair[Cpp.std.string, Cpp.std.unique_ptr[Cpp.Zoo]]('aviary', Cpp.std.move(aviary2)))

print(f'Zoo dict created? {zooDict}')

for key, val in zooDict:
    print(key, val)
    val.printAnimals()

返回:

IncrementalExecutor::executeFunction: symbol '_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10unique_ptrI3ZooSt14default_deleteISB_EEEEE9constructISF_JRS2_IS8_SE_EEEEvPT_DpOT0_' unresolved while linking symbol '__cf_13'!
You are probably missing the definition of void __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > > > >::construct<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<Zoo, std::default_delete<Zoo> > >&>(std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >*, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<Zoo, std::default_delete<Zoo> > >&)
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10unique_ptrI3ZooSt14default_deleteISB_EEEEE9constructISF_JPS2_IS8_SE_EEEEvPT_DpOT0_' unresolved while linking symbol '__cf_14'!
You are probably missing the definition of void __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > > > >::construct<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<Zoo, std::default_delete<Zoo> > >*>(std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::unique_ptr<Zoo, std::default_delete<Zoo> > >*, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<Zoo, std::default_delete<Zoo> > >*&&)
Maybe you need to load the corresponding shared library?

Zoo dict created? <cppyy.gbl.std.map<std::string,std::unique_ptr<Zoo,std::default_delete<Zoo> > > object at 0x55588a7f6fc0>
aquarium <cppyy.gbl.Zoo object at 0x55588a997be0 held by std::unique_ptr<Zoo,std::default_delete<Zoo> > at 0x55588b270bb0>
fish
aviary <cppyy.gbl.Zoo object at 0x55588a982cf0 held by std::unique_ptr<Zoo,std::default_delete<Zoo> > at 0x55588b364e00>
Birds

在第一次尝试时,但随后再次运行它返回:

Zoo dict created? <cppyy.gbl.std.map<std::string,std::unique_ptr<Zoo,std::default_delete<Zoo> > > object at 0x55588a7f6fc0>
aquarium <cppyy.gbl.Zoo object at 0x55588a997be0 held by std::unique_ptr<Zoo,std::default_delete<Zoo> > at 0x55588b270bb0>
fish
aviary <cppyy.gbl.Zoo object at 0x55588a982cf0 held by std::unique_ptr<Zoo,std::default_delete<Zoo> > at 0x55588b364e00>
Birds
python c++ std python-bindings cppyy

评论

0赞 shouriha 6/15/2023
@wim-lavrijsen:有什么建议吗?

答:

0赞 273K 6/15/2023 #1

std::map::emplace(Args&&... args)期望 中 ,该类型为 。std::map::value_typeargsstd::pair<const std::string, std::unique_ptr<Zoo>>

zooDict.emplace('aquarium', Cpp.std.move(aquarium2))

应该是 smth 喜欢(我不熟悉 cppyy)

zooDict.emplace(Cpp.std.make_pair('aquarium', Cpp.std.move(aquarium2)))

也许需要更改为'aquarium'Cpp.std.string('aquarium')