开发者

is back_insert_iterator<> safe to be passed by value?

开发者 https://www.devze.com 2022-12-25 03:21 出处:网络
I have a code that looks something like: struct Data { int value; }; class A { public: typedef std::deque<boost::shared_ptr<Data> > TList;

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_in开发者_如何学Csert_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 : )


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.


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;
}
0

精彩评论

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