views:

244

answers:

5

Is there a way to transfer ownership of the data contained in a std::vector (pointed to by, say T*data) into another construct, preventing having "data" become a dangling pointer after the vector goes out of scope?

EDIT: I DON'T WANT TO COPY THE DATA (which would be an easy but ineffective solution).

Specifically, I'd like to have something like:

template<typename T>
    T* transfer_ownership(vector<T>&v){
    T*data=&v[0];
    v.clear();
    ...//<--I'd like to make v's capacity 0 without freeing data 
}

int main(){
    T*data=NULL;
    {
        vector<double>v;
        ...//grow v dynamically
        data=transfer_ownership<double>(v);
    }
    ...//do something useful with data (user responsible  for freeing it later)
   // for example mxSetData(mxArray*A,double*data) from matlab's C interface
}

The only thing that comes to my mind to emulate this is:

{
    vector<double>*v=new vector<double>();
    //grow *v...
    data=(*v)[0];
}

and then data will later either be freed or (in my case) used as mxSetData(mxArray*A,double*data). However this results in a small memory leak (data struct for handling v's capacity, size, etc... but not the data itself of course).

Is it possible without leaking ?

+1  A: 

Does something like this work for you?

int main()
{
    double *data = 0;
    {
        vector<double> foo;
        // insert some elements to foo

        data = new double[foo.size()];
        std::copy(foo.begin(), foo.end(), &data[0]);
    }

    // Pass data to Matlab function.
    delete [] data;
    return 0;
}
Kristo
+4  A: 

A simple workaround would be swapping the vector with one you own:

vector<double> myown;

vector<double> someoneelses = foo();

std::swap( myown, someoneelses );

A tougher but maybe better approach is write your own allocator for the vector, and let it allocate out of a pool you maintain. No personal experience, but it's not too complicated.

xtofl
Simple, "clean" and very effective from perfomance perspective solution. myown can be created on heap or somewhere else, in order to live after someoneelses is out of scope.
Konstantin
or even shorter: `foo().swap(myown);`
sellibitze
Thanks for pointing out the custom allocators. I inherited allocator<T> into a allocator_derived<T> with custom behavior (being careful not to delete if some flag is set by the user, ie just before releasing the vector). This works great and doesn't leak with some care taken... on some systems but not all unfortunately. For example it works on mac (gcc 4.2.1) but on 64bit Linux (gcc 4.3), the vector declared as vector<T,allocator_derived<T> > doesn't even seem to use the derived behavior; I'm not sure why.
spirov
A: 

If your vector contains values you can only copy them (which happens when you call std::copy, std::swap, etc.). If you keep non-primitive objects in a vector and don't want to copy them (and use in another data structure), consider storing pointers

Dmitry
+5  A: 

The point of using a std::vector is not to have to worry about the data in it:

  • Keep your vector all along your application;
  • Pass it by const-ref to other functions (to avoid unnecessary copies);
  • And feed functions expecting a pointer-to-T with &v[0].

If you really don't want to keep your vector, you will have to copy your data -- you can't transfer ownership because std::vector guarantees it will destroy its content when going out-of-scope. In that case, use the std::copy() algorithm.

Julien L.
Matthieu M.
The third item is key, because passing the contents of the vector to the external functions without copying is big part of what the OP wants.
quark
A: 

Since you don't want to copy data between containers, but want to transfer ownership of data between containers, I suggest using a container of smart pointers as follows.

void f()
{
    std::vector<boost::shared_ptr<double> > doubles;
    InitVector(doubles);

    std::vector<boost::shared_ptr<double> > newDoubles(doubles);
}

You really can't transfer ownership of data between standard containers without making a copy of it, since standard containers always copy the data they encapsulate. If you want to minimize the overhead of copying expensive objects, then it is a good idea to use a reference-counted smart pointer to wrap your expensive data structure. boost::shared_ptr is suitable for this task since it is fairly cheap to make a copy of it.

Steve Guidi