2
votes

I've written a path class in my program for handling heirarchical path structures. I decided to use std::shared_ptr as the standard return type for the whole class since I'm getting rather fond it.

What surprised me is that I was unable to use std::copy or the normal vector.insert(v.begin(), v.end()) to copy elements to/from vectors of shared_ptr. Why is this?

shared_ptr<vector<shared_ptr<bfile>>> butils::bfile::search()
{
    shared_ptr<vector<shared_ptr<bfile>>> ret(new vector<shared_ptr<bfile>>());
    shared_ptr<vector<shared_ptr<bfile>>> children = getChildren();

    //WTF why don't either of these work?
    //std::copy(children->begin(), children->end(), back_inserter(ret));
    //ret->insert(children->begin(), children->end());

    //I've had to resort to doing this....
    for (auto c = children->begin(); c != children->end(); c++)
    {
        ret->push_back(*c);
        auto cChildren = (*c)->search();
        for (auto cc = cChildren->begin(); cc != cChildren->end(); cc ++)
        {
            ret->push_back(*cc);
        }
    }

    return ret;
}

When I tried the std::copy() I got:

1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\iterator(21): error C2039: 'const_reference' : is not a member of 'std::tr1::shared_ptr<_Ty>' 1> with 1> [ 1>
_Ty=std::vector> 1> ] 1>
BFile.cpp(329) : see reference to class template instantiation 'std::back_insert_iterator<_Container>' being compiled 1> with 1>
[ 1>
_Container=std::tr1::shared_ptr>> 1> ]

When I tried the insert(v.begin(), v.end()) I got;

1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory(208): error C2664: 'std::tr1::shared_ptr<_Ty>::shared_ptr(std::nullptr_t)' : cannot convert parameter 1 from 'std::_Vector_iterator<_Myvec>' to 'std::nullptr_t'
1>          with
1>          [
1>              _Ty=butils::bfile
1>          ]
1>          and
1>          [
1>              _Myvec=std::_Vector_val<std::tr1::shared_ptr<butils::bfile>,std::allocator<std::tr1::shared_ptr<butils::bfile>>>
1>          ]

I'm not sure I understand either of these compiler errors... Anyone else have a clue?

3
don't get too fond of shared_ptr, prefer using unique_ptr whenever there is no "shared" ownership. Shared ownership is a concept of its own, and should not be abused for the sake of ease as it carries its own woes (cycles of references) which can only be detected by memory leak tools... by experienced programmers. - Matthieu M.
@Matthieu - I take your point although given that the objects in question here are just path objects with a string and a bit of state in them it's difficult to see how they could result in a cycle of references. - Benj

3 Answers

9
votes

You're trying to make a back_inserter to the pointer to the vector, rather than the vector itself. Change back_inserter(ret) to back_inserter(*ret) (if you really feel the need to dynamically allocate vectors like that).

insert is failing because you're missing an argument:

ret->insert(ret->begin(), children->begin(), children->end());

The bizarre error message there is because there is a 2-argument overload of insert, with the second argument being an object to insert. The compiler tries to use this, but fails to convert the iterator into the object type.

2
votes

std::back_inserter expects a sequence, not a std::shared_ptr. Use back_inserter(*ret).

For the second, insert() requires a third parameter here: insert(where_to_insert,start,end)

0
votes

consider using a std::transform in place of std::copy.

std::transform(children->begin(), 
               children->end(), 
               back_inserter(ret),
               [](const bfile& in) { return make_shared<bfile>(in); });