[ptr_container] ptr_vector transfer from C array of pointers documentation

The documentation for ptr_vector::transfer( iterator before, T** from, size_type size, bool delete_from = true ) implies that the operation "delete [] from" is executed, but having examined the source, I don't think it is. This is actually the behaviour I need. I'm trying to convert a std::vector<T*> to a boost::ptr_vector<T*>, i.e. I have a vector of pointers which is solely responsible for "owning" the objects being pointed to, and I want to create a ptr_vector which will automatically clean up the objects when it goes out of scope. I need to do the transfer so that no memory leaks in the event of an exception. As far as I can see, this is exactly what ptr_vector::scoped_deleter is doing: it will delete any of the copied pointers, but it never actually deletes the "from" pointer; presumably because you don't know whether operator new[] was used when allocating it. Can anyone clear up/confirm that this will work: std::vector<T*> v1; v1.push_back(new T); boost::ptr_vector<T> v2; if (!v1.empty()) { v2.transfer(v2.end(), &v1[0], v1.size(), true); } // from this point, don't care about v1 and v2 will handle deletion of T objs Thanks, Simon

Number Cruncher skrev:
The documentation for ptr_vector::transfer( iterator before, T** from, size_type size, bool delete_from = true ) implies that the operation "delete [] from" is executed, but having examined the source, I don't think it is. This is actually the behaviour I need.
The docs could be slightly clearer, but I think they are close to optimal.
I'm trying to convert a std::vector<T*> to a boost::ptr_vector<T*>, i.e. I have a vector of pointers which is solely responsible for "owning" the objects being pointed to, and I want to create a ptr_vector which will automatically clean up the objects when it goes out of scope. I need to do the transfer so that no memory leaks in the event of an exception.
As far as I can see, this is exactly what ptr_vector::scoped_deleter is doing: it will delete any of the copied pointers, but it never actually deletes the "from" pointer; presumably because you don't know whether operator new[] was used when allocating it.
Actually it does call delete[] in any case as the destructor of scoped_deleter will call the destructor of the stored scoped_array member. scoped_deleter::release() only means that the T* objects are not deleted, but the internal array always is.
Can anyone clear up/confirm that this will work: std::vector<T*> v1; v1.push_back(new T);
boost::ptr_vector<T> v2; if (!v1.empty()) { v2.transfer(v2.end(), &v1[0], v1.size(), true); } // from this point, don't care about v1 and v2 will handle deletion of T objs
Well, a vector<T*> cannot guarantee that the internal buffer is allocated with new T[], I would say its almost guaranteed that it is not. IOW, the function is meant for C-arrays allocated with new T[], not vectors. So no, it won't work. replacing true with false makes it work, but ... You can still get a leak if insertion fails, but how is that any worse than what your current code can do? Otherwise, use scoped_deleter manually as so: v2.scoped_deleter sd( v2, v1.size() ); std::copy( v1.begin(), v1.end(), sd.begin() ); v2.transfer( v2.end(), sd.begin(), v1.size(), false ); sd.release(); <remark> It would have been possible to do v1.swap(v2.base()) if it was not for the use of void* internally. Its on my agenda to change this in the future </remark> A question: why don't you just use ptr_vector where it's needed? Is it s legacy issue? HTH -Thorsten

On 28/07/10 16:36, Thorsten Ottosen wrote:
As far as I can see, this is exactly what ptr_vector::scoped_deleter is doing: it will delete any of the copied pointers, but it never actually deletes the "from" pointer; presumably because you don't know whether operator new[] was used when allocating it.
Actually it does call delete[] in any case as the destructor of scoped_deleter will call the destructor of the stored scoped_array member. scoped_deleter::release() only means that the T* objects are not deleted, but the internal array always is.
Thanks; I missed the scoped_array member storage.
Well, a vector<T*> cannot guarantee that the internal buffer is allocated with new T[], I would say its almost guaranteed that it is not. IOW, the function is meant for C-arrays allocated with new T[], not vectors. So no, it won't work. replacing true with false makes it work, but ...
Yes; I never wanted the ptr_vector to try and clear up the std::vector's internal array or pointers - just the pointees.
You can still get a leak if insertion fails, but how is that any worse than what your current code can do? Otherwise, use scoped_deleter manually as so:
v2.scoped_deleter sd( v2, v1.size() ); std::copy( v1.begin(), v1.end(), sd.begin() ); v2.transfer( v2.end(), sd.begin(), v1.size(), false ); sd.release();
I can see how that might work...
A question: why don't you just use ptr_vector where it's needed? Is it s legacy issue?
It all started when I needed to return a list of (shallow, non-owning) observer pointers from a class. Sometimes that class would create and own the pointees itself and sometimes it would just be another indirection to an external source. I see that I can use view_clone_allocator to remove ownership semantics, but I can't return "const ptr_vector<T, heap_clone_allocator> &" one moment and const ptr_vector<T, view_clone_allocator> &" the next. I ended up storing a (possibly empty) ptr_vector in the class, and returning "const std::vector<T *> &" with shallow pointer copies of the ptr_vector contents if owned, and the indirected pointers otherwise. If there were no legacy issues at all, I'd probably just return a std::vector<shared_ptr>. Regards, Simon.
participants (2)
-
Number Cruncher
-
Thorsten Ottosen