tags:

views:

78

answers:

2

I have a code that looks something like:

struct Data { int value; };
class A {
public:
    typedef std::deque<boost::shared_ptr<Data> > TList;
    std::back_insert_iterator<TList> GetInserter()
    {
        return std::back_inserter(m_List);
    }
private:
    TList m_List;
};
class AA {
    boost::scoped_ptr<A> m_a;
public:
    AA() : m_a(new A()) {}
    std::back_insert_iterator<A::TList> GetDataInserter()
    {
        return m_a->GetInserter();
    }        
};
class B {
    template<class OutIt>
    CopyInterestingDataTo(OutIt outIt)
    {
        // loop and check conditions for interesting data
        // for every `it` in a Container<Data*>
        // create a copy and store it
        for( ... it = ..; .. ; ..) if (...) {
            *outIt = OutIt::container_type::value_type(new Data(**it));
            outIt++; // dummy
        }
    }
    void func()
    {
        AA aa;
        CopyInterestingDataTo(aa.GetDataInserter());
        // aa.m_a->m_List is empty!
    }
};

The problem is that A::m_List is always empty even after CopyInterestingDataTo() is called. However, if I debug and step into CopyInterestingDataTo(), the iterator does store the supposedly inserted data!

update: I found the culprit. I actually have something like:

class AA {
    boost::scoped_ptr<A> m_a;
    std::back_insert_iterator<A::TList> GetDataInserter()
    {
        //return m_a->GetInserter(); // wrong
        return m_A->GetInserter(); // this is the one I actually want
    }        
    // ..... somewhere at the end of the file
    boost::scoped_ptr<A> m_A;
};

Now, which answer should I mark as answer? Really sorry for those not chosen, but you guys definitely got some up-votes : )

+4  A: 

The short answer is yes, back_insert_iterator is safe to pass by value. The long answer: From standard 24.4.2/3:

Insert iterators satisfy the requirements of output iterators.

And 24.1.2/1

A class or a built-in type X satisfies the requirements of an output iterator if X is an Assignable type (23.1) ...

And finally from Table 64 in 23.1:

expression t = u return-type T& post-condition t is equivalent to u

EDIT: At a glance your code looks OK to me, are you 100% certain that elements are actually being inserted? If you are I would single step through the code and check the address of the aa.m_a->m_List object and compare it to the one stored in outIt in CopyInterestingDataTo, if they're not the same something's fishy.

Andreas Brinck
Great info. I expected it to be safe. Now, should I change my question to "what is wrong with my code?" instead?
afriza
I don't think so. Your question was answered, so mark the answer accepted and leave the question as it is. It didn't solve the actual problem you're having though, so ask another question about *that*. (and please, something more specific than "what is wrong with my code" :)
jalf
+1  A: 

The following code, which compiles, prints "1", indicating one item added to the list:

#include <iostream>
#include <deque>
#include "boost/shared_ptr.hpp"
#include "boost/scoped_ptr.hpp"

struct Data { 
    int value; 
    Data( int n ) : value(n) {}
};

struct A {
    typedef std::deque<boost::shared_ptr<Data> > TList;
    std::back_insert_iterator<TList> GetInserter()
    {
        return std::back_inserter(m_List);
    }
    TList m_List;
};

struct AA {
    boost::scoped_ptr<A> m_a;
    AA() : m_a(new A()) {}
    std::back_insert_iterator<A::TList> GetDataInserter()
    {
        return m_a->GetInserter();
    }        
};

struct B {
    template<class OutIt>
    void CopyInterestingDataTo(OutIt outIt)
    {
        *outIt = typename OutIt::container_type::value_type(new Data(0));
        outIt++; // dummy
    }
    int func()
    {
        AA aa;
        CopyInterestingDataTo(aa.GetDataInserter());
        return aa.m_a->m_List.size();
    }
};

int main() {
    B b;
    int n = b.func();    
    std::cout <<  n << std::endl;
}
anon
now, something is really strange with my real code then. :S
afriza