【问题标题】:Erasing element from Vector in function在函数中从 Vector 中擦除元素
【发布时间】:2011-11-03 08:22:43
【问题描述】:

在 C++ 中,除了我的问题Erasing element from Vector,我如何将删除向量中的元素的方法推广到一个接受以下参数的函数中:向量,以及要从此向量中删除的元素?

bool removeElementFromVector(vector * collection, void * element) {
    for(int i=0; i<collection->size(); i++){
        if (collection[i]==element){
            swap(collection[i], collection.back());
            collection.pop_back();
            return true;
        }
    }
}

我的问题是我不知道参数列表必须是什么样子才能使其能够与 any vector&lt;whatever*&gt; 和任何对象 whatever 一起使用! ?

编辑:解决方案:

myfunctions.h

template <typename T>
bool removeElementFromVector(vector<T> & collection, T const & element) { 
    // for... 
}

myclass.h

#include "myfunctions.h"
public:
vector<Item*> items;                        
void removeItem(Item * item);          

myclass.cpp

#include "myclass.h"
void myclass::removeItem(Item * item) {
    removeElementFromVector(this->items, item);
}

【问题讨论】:

  • 矢量类是什么样的? std::vector 肯定会采用类似 vector->erase(element); 的东西。例如。
  • @Valmond,vector::eraseO(n),OP 的方法是 O(1)(虽然它弄乱了元素的顺序)。
  • OP 不关心顺序 ;)

标签: c++


【解决方案1】:

在 C++ 中,编写适用于不同类型的通用代码的类型安全方法不是传递void*,而是传递模板。在您的特定情况下:

template <typename T>
void removeElement( std::vector<T> & collection, T const & element ) {
   collection.erase( std::remove( collection.begin(), collection.end(), element ),
                     collection.end() );
}

通过在包含的类型T 上使用模板,您可以使其成为泛型。在内部,从向量中删除元素的惯用语是 erase-remove 惯用语,它将删除匹配的元素,并向前压缩其余元素,保持相对顺序。我已经更改了引用的指针。如果您的容器持有指向给定类型的指针,并且传递的元素是指向该类型的指针,编译器将为您推断 Ttype*,但上面的代码也适用于不持有指针的容器(更通用一点)

如果相对顺序不重要,您可以使用与您的问题相同的循环,这样效率会更高(副本数量更少)。

【讨论】:

  • 为什么要使用引用而不是指针?我尝试按如下方式使用它:vector&lt;Item*&gt; items; removeElement(items, item); 但我收到编译器错误:未定义对bool removeElement&lt;Item*&gt;(std::vector&lt;Item*, std::allocator&lt;Item*&gt; &gt;&amp;, Item* const&amp;) 的引用有什么帮助吗?
  • @Ben:“为什么我应该使用引用而不是指针?”引用更容易正确使用,因为您不必处理它们为空的可能性,并且您不会意外更改它们引用的对象。
  • @Ben:“有什么帮助吗?”我猜您将模板定义放在源文件中。你必须把它放在一个头文件中,并从任何使用它的文件中包含它。
  • @Mike:谢谢,我已经编辑了我的原始帖子,以包含我如何定义和调用它的所有细节。我做错了什么?
  • @Ben:您需要将函数模板的定义从“myfunctions.cpp”移动到“myfunctions.h”。通常,模板定义必须在头文件中,因为它们必须在使用模板的任何地方都可用。
【解决方案2】:

你应该把函数做成模板:

template <typename T>
bool removeElementFromVector(vector<T> & collection, T const & element);

另外,不要使用指针。

【讨论】:

    【解决方案3】:

    使函数成为模板:

    template <typename T>
    bool removeElementFromVector(vector<T*> * collection, T* element) {
        for(int i=0; i<collection->size(); i++){
            if (collection[i]==element){
                swap(collection[i], collection.back());
                collection.pop_back();
                return true;
            }
        }
    }
    

    另一方面,您的代码对于所有这些指针都相当糟糕。标准容器旨在存储完整的对象,而不仅仅是指针。同样,element 参数很容易成为 (const) 引用。

    【讨论】:

      猜你喜欢
      • 2019-09-09
      • 1970-01-01
      • 1970-01-01
      • 2011-09-30
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-05
      相关资源
      最近更新 更多