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;
}
};
精彩评论