开发者

Deep copy of std::stack< boost::shared_ptr<T> >

I would like to implement a copy of std::stack< boost::shared_ptr<T> >. Is there any way to do it without 3 copies? Here is the code:

template<typename T>
void copyStackContent(std::stack< boost::shared_ptr<T> > & dst,
                      std::stack< boost::shared_ptr<T> > const & src){

    //// Copy stack to temporary stack so we can unroll it
    std::stack< boost::shared_ptr<T> > tempStack(src);

    /// Copy stack to array
    std::vector< boost::shared_ptr<T> > tempArray;
    while(!tempSt开发者_如何学JAVAack.empty()){
        tempArray.push_back(tempStack.top());
        tempStack.pop();
    }

    /// Clear destination stack
    while(!dst.empty()){
        dst.pop();
    }

    /// Create destination stack
    for(std::vector< boost::shared_ptr<T> >::reverse_iterator it =
        tempArray.rbegin(); it != tempArray.rend(); ++it){
        dst.push( boost::shared_ptr<T>(new T(**it)) );
    }
}

And a sample test:

void test(){
    // filling stack source
    std::stack< boost::shared_ptr<int> > intStack1;
    intStack1.push( boost::shared_ptr<int>(new int(0)) );
    intStack1.push( boost::shared_ptr<int>(new int(1)) );
    intStack1.push( boost::shared_ptr<int>(new int(2)) );
    intStack1.push( boost::shared_ptr<int>(new int(3)) );
    intStack1.push( boost::shared_ptr<int>(new int(4)) );

    // filling stack dest
    std::stack< boost::shared_ptr<int> > intStack2;
    copyStackContent(intStack2, intStack1);

    assert(intStack1.size() == intStack2.size());         // same size
    while(!intStack1.empty()){
        assert(intStack1.top() != intStack2.top());       // != pointers
        assert((*intStack1.top()) == (*intStack2.top())); // same content
        intStack1.pop();
        intStack2.pop();
    }
}


If you want to maintain the ordering, you're kind of stuck since stack doesn't provide any iterators. If you don't want to use a deque, you can at least make the code clearer (and more efficient under certain circumstances) by passing the source stack by value:

template<typename T>
void copyStackContent(std::stack< boost::shared_ptr<T> > & dst,
                      std::stack< boost::shared_ptr<T> > src){

    // Copy stack to array
    std::vector< boost::shared_ptr<T> > tempArray;
    while(!tempStack.empty()){
        tempArray.push_back(tempStack.top());
        tempStack.pop();
    }

    // Clear destination stack
    while(!dst.empty()){
        dst.pop();
    }

    // Create destination stack
    for(std::vector< boost::shared_ptr<T> >::reverse_iterator it =
        tempArray.rbegin(); it != tempArray.rend(); ++it){
        dst.push( boost::shared_ptr<T>(new T(**it)) );
    }
}

Though, I am suspicious of copying the values pointed to by shared_ptrs. Why even dynamically allocate if you're going to be copying everything anyhow?


In this case your best bet is to probably just use a deque instead of a stack and change top to back etc as needed. Then you can iterate and do the deep copy in one pass.

Alternately figure out why you need the deep copy and try to remove that need at its source.


No, what you have is about as efficient as you're going to get. However, if you find yourself doing this, you should probably simply use a std::vector or std::deque instead of a stack. std::stack is merely a wrapper around one of these containers (usually std::deque) If you use either of these containers, you can effectively reverse the sequence by using reverse iterators, and if you're using a std::deque, you can even insert on the other side efficiently using push_front.

Side note: You should also probably have copyStackContent return a new stack instead of taking a destination stack by reference. It's more readable, and it can be cheaper to allocate a new stack and simply deallocate the old one than to erase all the elements from the existing stack.


My first answer was daft, didn't read the whole question, here is a clean implementation of a clone operation for stack bringing together the ideas discussed above, but using stacks only...

template <typename T, typename _CT = boost::shared_ptr<T>, typename _ST = std::stack<_CT> >
struct cloner
{
  inline _CT copy(_CT t)
  {
    return _CT(new T(*t));
  }

  _ST operator()(_ST src)
  {
    _ST temp;

    while(!src.empty())
    {
      temp.push(copy(src.top()));
      src.pop();
    }

    while(!temp.empty())
    {
      src.push(temp.top());
      temp.pop();
    }
    return src;
  }
};
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜