C++模板函数,接收std::vector作为参数

5

我需要创建一个模板函数,它的参数是某种类型的std::container,比如说std::vector,并且可以删除该容器中的所有元素。我需要一个等效于以下函数的函数:

for_each(some_vector.begin(), some_vector.end(), [](some_vector_type* element){delete element;}); 

调用应该是这样的:
delete_all_elements(some_vector);

这个有可能实现吗?

编辑:我想在delete_all_elements中使用第一段代码。


12
你正在使用C++11,仍然写delete?你确定不能用std::vector<std::unique_ptr<T>>来使问题消失吗? - Alexandre C.
作为额外的答案:如果您删除了一些指针,请在最后将这些已删除的指针放置到NULL(或C++11的nullptr)中,或从容器中删除这些指针(除非您确定容器本身很快就会被销毁)。拥有悬空指针不是一个好的设计选择... :-) ... 阅读所有答案,我惊讶地发现没有人会做最后的清理。 - paercebal
使用std::unique_ptr消除问题的另一个原因是,当您想要一个指向数组第一个元素的指针向量时,而不是单个对象时,可以切换到std::unique_ptr<T[]>的向量。否则,您将不得不编写一个与delete_all_elements相同但使用delete[]而不是deletedelete_all_array_elements函数,然后在没有类型系统帮助的情况下调用正确的函数。 - Steve Jessop
4个回答

14

为什么不是呢?

template <typename C>
void delete_all_elements(C& container) {
    std::for_each(
        container.begin(), container.end(),
        [](typename C::value_type ptr) { delete ptr; }
    );
    container.clear();
}
您可以在开头添加例如 static_assert(std::is_pointer<typename C::value_type>::value, "Elements must be pointers"); 以确保您不会尝试删除非指针。

谢谢!我不知道C :: value_type。 - Mircea Ispas
在这种情况下,我认为没有什么区别。但是,在这种类型的情况下,使用C::reference作为默认值可能是值得的,以防止代码更改时发生意外复制。 - Martin York
1
如果你将容器引用传递给其他函数,请在最后添加 container.clear(),以免留下悬空指针的容器。 - Dave S

1

为什么不像几乎每个STL算法那样做:

template<typename Iterator>
void delete_all_elements(Iterator begin, Iterator end) {
    while (begin != end) {
        delete *begin;
        ++begin;
    }
}

1

规范的方法是:

template <typename I>
void delete_all_elements(I begin, I end)
{
    for (; begin != end; ++begin) delete *begin;
}

0
你是否在寻找这个(C++03解决方案):
template<typename Container>
void delete_all(const Container & c)
{
   typename Container::const_iterator begin = c.begin(), end = c.end();
   while ( begin != end ) { delete *begin; ++begin; }
}

2
我可能错了,但是接受const容器作为您的“全部删除”函数是不好的风格:虽然合法,但您仍在语义上修改容器内部的值(破坏容器内部的对象)。 - paercebal
2
希望现在没问题了。而且const并不是问题。const int *p = new int; delete p; 完美无误!是的,我知道。这就是为什么我在我的评论中写了“虽然合法”。但从语义上讲,这是错误的,因为无论间接性如何(在这里,是“双指针”),容器的每个项目都包含一个指向有效对象的值。在函数结束时,这些值不再指向有效对象(它们已被销毁)。因此,在某种程度上,您修改了容器,这是您在函数原型中声明为const时承诺不会做的事情。 - paercebal
2
Nawaz:并不是说这是非法的,但这是一种不好的形式,因为该函数暗示它不会改变数据的公共内容,但随后却炸掉了所有指针。 - Dave S
2
@Nawaz: 如果你将它变成非const,那么你就不能在const向量上调用这个函数。 当然!这正是重点:重点不是尽可能地赋予函数更多的权力,而是使接口(这里是函数原型)在用户查看时尽可能清晰:const在这里告诉用户“我保证不会触及你的容器内容”。然后,在函数体中,你破坏了向量的内容。这意味着你欺骗了用户,这是语义上错误的。 - paercebal
1
@paercebal:C++03标准要求所有容器的end操作都是常数时间操作。 - David Rodríguez - dribeas
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接