如何为在 std::map 中存储指针的模板类编写复制构造函数

How to write a copy constructor for a template class that stores pointers in a std::map?

本文关键字:构造函数 复制 存储 std map 指针      更新时间:2023-10-16

我刚开始使用 c++,我在制作一个名为 auto_map 的模板类时遇到了一些问题,该模板类使用 std::map,它必须存储的不是对象,而是它们的指针。

像这样:

std::map<K*, V*, cmp> m;

我像这样使用:

auto_map<std::string, std::string> t;
t.insert( new std::string( "A" ), new std::string( "B" ) );

CPM是:

struct cmp
{
  bool operator()(K *a, K *b) { return *a < *b; }
  bool operator== (K *a) { return (*a); }
};
插入

函数在插入之前搜索任何重复项:

void insert(K* k, V* v)
{
  for (typename std::map<K*, V*, cmp>::iterator i=m.begin(); i!=m.end(); ++i)
  {
    if ( (*k) == (*(*i).first) ) 
    {
      delete (*i).first;
      delete (*i).second;
      m.erase(i);
    }          
  }
  m.insert(std::make_pair(k,v));
}

和构造函数:

auto_map(){}
~auto_map()
{
  for (typename std::map<K*, V*, cmp>::iterator i=m.begin(); i!=m.end(); ++i)
  { 
    delete (*i).first;
    delete (*i).second;
    m.erase(i);
  }
}

这些工作正常,但现在您可能明白了。所以问题来了,我不太确定:

如何为它编写复制构造函数?

auto_map (auto_map& original)
{
  for (typename std::map<K*, V*, cmp>::iterator i=original.m.begin(); i!=original.m.end(); ++i)
  {
    // what goes in here that will call each objects copy-constructor?
    // how not to get complained about invalid conversions?... 
    // K newk = (*(*i).first);
    // V newv = (*(*i).second);
    // m.insert(std::make_pair(newk, newv));
    // gives compiler error: cannot convert ‘const CntInteger’ to ‘CntInteger* const’ in initialization
    // cannot convert ‘const CntInteger’ to ‘CntInteger*’ in initialization

  }
};

非常感谢您的回答和更正!

要从标题中回答您的字面问题:您不能为现有类模板编写新的复制构造函数std::map

接下来,您确定是否真的要再次通过 O(log n( 查找为您的容器实现映射的整个(二叉树(结构,并添加std::shared_ptr的内存管理注意事项(考虑具有自定义删除器的对象(?为什么不简单地将shared_ptr放入地图中?

std::map<std::shared_ptr<Key>, std::shared_ptr<Value>>

更新:你能使用Boost的指针容器吗?还是你也需要你的价值观成为指针?值T*boost::ptr_unordered_map<std::string, T>怎么样?

虽然我怀疑您要做的事情的效用,但您来了:

auto_map (auto_map& original)
{
    K * kp = 0;
    V * vp = 0;
    try
    {
        for (typename std::map<K*, V*, cmp>::iterator i=original.m.begin();
             i!=original.m.end();
             ++i, kp=0, vp=0)
        {
            kp = new K(*(i->first));
            vp = new V(*(i->second));
            m[kp] = vp;                  
        }
    }
    catch(...)
    {
        delete kp;
        delete vp;
        // write a destroy function that does the same thing
        // as your destructor does now
        destroy();
        throw;       
    }
}