如何高性能的实现queue的清除

1 篇文章 0 订阅

在写leetcode的时候,遇到一个问题,有queue q1,每次循环都需要将q1清除,心里一直有一个疑问,对于这样的元素怎么清除才是最高效的?

下面用有限的知识简单写一下下自己的理解,如有错误,欢迎指出。

原理分析

于是开启了搜索答案之路:在stackoverflow的答案上 how-do-i-clear-the-stdqueue-efficiently,一个高赞答案是和一个空的container进行swap操作(swapping with an empty version of the container)
具体代码如下:

void clear( std::queue<int> &q )
{
   std::queue<int> empty;
   std::swap( q, empty );
}

那问题就来到了:为什么采用swap函数是高效的?
在我们的记忆中,swap函数其实是生成了一个中间对象,再通过交换操作,进行互换。标准库的swap实现就调用了拷贝构造函数(对于非内置类型),并且有两次的赋值运算,这在很多情况下是不满足我们的效率需求的(大型对象的拷贝是毫无必要的操作,我们仅需要交换指针,若存在容器类型,调用容器类的swap明显是更加正确的操作)。
在C++11中,我们有如下的优化:当用户实现了移动赋值运算符 那么swap本质用的是移动赋值运算符 如果没有实现移动赋值运算符 那么swap使用的就是拷贝赋值运算符 而拷贝赋值运算符意味着又有构造也有析构 这就是资源浪费的根源 因为是有机会避免进行这些构造析构的

template<typename T>
void swap(T& a,T&b) {
    T temp(std::move(a));
    a = std::move(b);
    b = std::move(temp);
    ...
}

移动方式move的本质就是移交临时对象对资源的控制权,通常就是指针的替换,因此上述操作对存在移动构造和移动赋值运算的类来讲,已经可以基本满足要求。
为了帮助更好的理解move的用法,下面给出了一个move的例子(详细了解move用法可参考what-is-move-semantics)

auto_ptr<Shape> a(new Triangle);

      +---------------+
      | triangle data |
      +---------------+
        ^
        |
        |
        |
  +-----|---+
  |   +-|-+ |
a | p | | | |
  |   +---+ |
  +---------+

auto_ptr<Shape> b(a);

      +---------------+
      | triangle data |
      +---------------+
        ^
        |
        +----------------------+
                               |
  +---------+            +-----|---+
  |   +---+ |            |   +-|-+ |
a | p |   | |          b | p | | | |
  |   +---+ |            |   +---+ |
  +---------+            +---------+

我们可以看到用a去初始化b时,没有新建一个对象,而是将a的控制权移交到了b上(a is moved into b)
针对queue,swap函数实际应用的是移动赋值运算,而不进行实际意义的拷贝,可以减少构造和构析的时间。queue<int> empty则是在函数内部定义的,当函数结束时empty所在的空间会释放,在之前通过swap( q, empty )empty所指在空间已经变为q在的空间了,因此会被回收。在跳出函数之后,q现在是一个空的新空间了。

实验测试

void clear(queue<int> &q){
    queue<int> empty;
    swap(q, empty);
}

void fun1(){
    queue<int> q;
    for(int i=0; i<1000; ++i){
        for(int j=0; j<1000; ++j){
            q.push(j);
        }
        clear(q);
    }
}
void fun2(){
    queue<int> q;
    for(int i=0; i<1000; ++i){
        for(int j=0; j<1000; ++j){
            q.push(j);
        }
        while(q.size()) q.pop();
    }
}

对fun1和fun2进行测试,运行所用时间结果如下:

time1 = 0.062731s
time2 = 0.077654s

由此可以看到我们写的clear方法的高效性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值