3

我用 C++ 编写了一个小型测试实体管理器。我有一个使用简单擦除的名为“removeEntityByName”的方法。直到这里没有问题。现在我有另一个方法叫做'removeEntityByPtr',它必须按值删除。这是有效的代码:

void EntityManager::removeEntityByPtr(Entity *pEntity)
{
    std::map<std::string, Entity*>::iterator It = this->m_EntityList.begin();

    for (; It != this->m_EntityList.end();) {
        if ((*It).second == pEntity) {
            this->m_EntityList.erase(It++);
        } else {
            ++It;
        }
    }
}

但它不是很漂亮。所以,我想知道我是否可以找到一种更优雅的方式,使用 STL 算法和仿函数来正确完成这项工作(我知道 std::vector 没有问题,但 std::map 我不确定它是否有效)。所以这是我尝试使用的不同仿函数:

template <typename T>
struct DeleteFunctor
{
    DeleteFunctor(T *pointer)
        :   m_Pointer(pointer)
    {

    }

    bool operator()(std::string, Entity *pEntity)
    {
        if (pEntity == this->m_Pointer) {
            delete(this->m_Pointer);
            return (true);
        }
        return (false);
    }

    T *m_Pointer;
};

template <typename T>
struct DeleteFunctor
{
    DeleteFunctor(T *pointer)
        :   m_Pointer(pointer)
    {

    }

    bool operator()(std::pair<std::string, Entity*> const &cell)
    {
        if (cell.second == this->m_Pointer) {
            delete(this->m_Pointer);
            return (true);
        }
        return (false);
    }

    T *m_Pointer;
};

和 STL 算法:

this->m_EntityList.erase(std::remove(this->m_EntityList.begin(), this->m_EntityList.end(), DeleteFunctor<Entity>(pEntity)), this->m_EntityList.end());

我想准确地说 Visual Studio 的语法是正确的。但是编译失败了。

这是编译错误:

error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::pair<_Ty1,_Ty2>'
 with
[
   _Ty1=const std::string,
   _Ty2=Entity *
]
c:\program files (x86)\microsoft visual studio 11.0\vc\include\exception(507): peut être 'bool std::operator ==(const std::exception_ptr &,const std::exception_ptr &)'
c:\program files (x86)\microsoft visual studio 11.0\vc\include\exception(512): ou       'bool std::operator ==(std::nullptr_t,const std::exception_ptr &)'
c:\program files (x86)\microsoft visual studio 11.0\vc\include\exception(517): ou       'bool std::operator ==(const std::exception_ptr &,std::nullptr_t)'
c:\program files (x86)\microsoft visual studio 11.0\vc\include\system_error(426): ou       'bool std::operator ==(const std::error_code &,const std::error_condition &) throw()'
c:\program files (x86)\microsoft visual studio 11.0\vc\include\system_error(434): ou       'bool std::operator ==(const std::error_condition &,const std::error_code &) throw()'
when attempting matching of the argument list '(std::pair<_Ty1,_Ty2>, const DeleteFunctor)'
with
[
  _Ty1=const std::string,
  _Ty2=Entity *
]
c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm(1788) : see the reference of the model function '_FwdIt std::_Remove<std::_Tree_unchecked_iterator<_Mytree>,_Ty>(_FwdIt,_FwdIt,const _Ty &)' en cours de compilation
with
[     _FwdIt=std::_Tree_unchecked_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,Entity *>>>>,
 _Mytree=std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,Entity *>>>,
 _Ty=DeleteFunctor
]
c:\users\volodia\desktop\testmanager\testmanager\entitymanager.cpp(76) : voir la référence à l'instanciation de la fonction modèle '_FwdIt std::remove<std::_Tree_iterator<_Mytree>,DeleteFunctor>(_FwdIt,_FwdIt,const _Ty &)' en cours de compilation
with
[
 _FwdIt=std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,Entity *>>>>,
  _Mytree=std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,Entity *>>>,
  _Ty=DeleteFunctor
]

我尝试了几种代码组合,但均未成功。有人可以帮助我吗?非常感谢您的帮助。

4

1 回答 1

3

许多算法,包括std::remove通过在容器中移动元素来工作。例如,std::remove将不需要的元素交换到后面,将想要的元素交换到前面。

std::map这在和之类的关联容器中是不允许的std::set,因为存储元素的顺序是固定的,因此您不能在容器上使用这些算法。

话虽如此,您所做的第一种方法是正确的,尽管您可以将算法与逻辑分开:

template <class Container, class Pred>
void erase_if(Container& cont, Pred pred) {
  for (auto first = begin(cont), last = end(cont); first != last;)
  {
    if (pred(*first))
      first = cont.erase(first);
    else
      ++first;
  }
}

然后在您的代码中(C++14 风格):

void EntityManager::removeEntityByPtr(Entity *pEntity)
{
  erase_if(this->m_EntityList, [=](auto const& keyValue) { 
    return keyValue.second == pEntity;
  }
}

在 C++11中,您必须指定 lambda 函数参数的类型,即std::pair<std::string const, Entity*>.
在 C++03中,您必须滚动一个额外的仿函数,在erase_iffor 循环中指定迭代器类型,就像您在示例中所做的那样,并调用容器的beginend成员函数,而不是 C++11 中引入的自由函数

于 2013-08-22T09:22:11.603 回答