Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is there an elegant way to transfer a subset of one deque to another?

Tags:

c++

deque

By using boost perhaps or another way?

I want to create a function, to grab a subset of deque d from (and including) index iStart to index 0, into a new deque, but also to set that those values in d to 0. I thought about this:

std::deque<int> CreateSubset(std::deque<int>& d, int iStart )
{
   int iSubsetSize = iStart+1;
   std::deque<int> subset(iSubsetSize); // initialise a deque of a certain size.

   std::deque<int>::iterator it = d.begin();

   subset.assign (it, d.begin()+iStart+1);

   for(;it != d.begin()+iStart+2; it++)
   {
     *it = 0;
   }  
   return subset;
}

But it looks horrible to me - is there a nicer way?

like image 263
BeeBand Avatar asked Jun 23 '13 13:06

BeeBand


People also ask

Is a deque contiguous?

As opposed to std::vector, the elements of a deque are not stored contiguously: typical implementations use a sequence of individually allocated fixed-size arrays, with additional bookkeeping, which means indexed access to deque must perform two pointer dereferences, compared to vector's indexed access which performs ...

What is STL deque?

In C++, the STL deque is a sequential container that provides the functionality of a double-ended queue data structure. In a regular queue, elements are added from the rear and removed from the front. However, in a deque, we can insert and remove elements from both the front and rear.

Is deque synchronized?

The deque has to keep track of how many elements it has and where those elements are. Adding an element changes that stored data, as does removing an element. Changing that data from two threads without synchronization is a data race, and produces undefined behavior. In short, you must synchronize those operations.


1 Answers

Here is how I'd do it in C++11. I believe the code is fairly elegant, and I don't think there is anything particularly inefficient about it:

#include <iostream>
#include <deque>
#include <iterator>
#include <algorithm>

template <typename ForwardIt>
std::deque<int> extract(ForwardIt from, ForwardIt to)
{
  using std::make_move_iterator;

  std::deque<int> d2(make_move_iterator(from),
                     make_move_iterator(to));
  std::fill(from,to,0);

  return d2;
}

The extract() function template takes two forward iterators, moves the content between them to a newly created deque and sets it to 0 in the original.

The template as written makes two assumptions:

  1. Although the source iterators may refer to anything, the destination is always a deque;
  2. The default value you want to reset the original elements to is 0.

Both assumptions can be relaxed by introducing further template parameters or function arguments.

As you can see, I use std::make_move_iterator to convert the input iterators to move iterators, thus causing the elements to be moved (rather than copied) to the destination. As long as these are int, it won't really make a difference, though.

I use the std::fill algorithm to set the original elements to 0.

This is how you could call this function template:

int main()
{
  /* Creating d. */
  std::deque<int> d
  { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 };

  /* Extracting the first three elements into a new deque. */
  auto d2 = extract(begin(d),begin(d) + 3);

  /* Printing the results. */    
  std::cout << "d:\n";
  for (const auto &elem : d)
    std::cout << elem << ',';

  std::cout << "\n\nd2:\n";
  for (const auto &elem : d2)
    std::cout << elem << ',';

  std::cout << std::endl;
  return 0;
}
like image 87
jogojapan Avatar answered Sep 24 '22 07:09

jogojapan