предотвращение освобождения данных, когда вектор выходит из области видимости - PullRequest
6 голосов
/ 13 ноября 2009

Есть ли способ перенести владение данными, содержащимися в std :: vector (на которые указывают, скажем, T * data), в другую конструкцию, предотвращая превращение «данных» в висячий указатель после выхода вектора из области

РЕДАКТИРОВАТЬ: Я НЕ ХОЧУ КОПИРОВАТЬ ДАННЫЕ (это было бы простым, но неэффективным решением).

В частности, я бы хотел что-то вроде:

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
}

Единственное, что приходит мне на ум, это подражать:

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

и затем данные будут либо освобождены, либо (в моем случае) использованы как mxSetData (mxArray A, double data). Однако это приводит к небольшой утечке памяти (структура данных для управления емкостью, размером и т. Д., Но не сами данные, конечно).

Возможно ли это без утечки?

Ответы [ 5 ]

6 голосов
/ 13 ноября 2009

Простой обходной путь - заменить вектор на свой:

vector<double> myown;

vector<double> someoneelses = foo();

std::swap( myown, someoneelses );

Более сложный, но, возможно, лучший подход - написать свой собственный распределитель для вектора и позволить ему выделять из пула, который вы поддерживаете. Нет личного опыта, но это не слишком сложно.

5 голосов
/ 13 ноября 2009

Смысл использования std :: vector не в том, чтобы беспокоиться о данных в нем:

  • Держите свой вектор на всем протяжении вашего приложения;
  • Передать его по const-ref другим функциям (чтобы избежать ненужных копий);
  • И функции подачи, ожидающие указатель на T с &v[0].

Если вы действительно не хотите сохранять свой вектор, вам придется скопировать свои данные - вы не можете передать право собственности, потому что std::vector гарантирует, что он разрушит его содержимое при выходе из области видимости. В этом случае используйте алгоритм std::copy().

1 голос
/ 13 ноября 2009

Если ваш вектор содержит значения, вы можете только скопировать их (что происходит, когда вы вызываете std :: copy, std :: swap и т. Д.). Если вы храните непримитивные объекты в векторе и не хотите копировать их (и используете в другой структуре данных), рассмотрите возможность хранения указателей

0 голосов
/ 13 ноября 2009

Поскольку вы не хотите копировать данные между контейнерами, но хотите передать право собственности на данные между контейнерами, я предлагаю использовать контейнер интеллектуальных указателей следующим образом.

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

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

Вы действительно не можете передать право собственности на данные между стандартными контейнерами, не сделав их копию, поскольку стандартные контейнеры всегда копируют инкапсулированные данные. Если вы хотите минимизировать накладные расходы при копировании дорогих объектов, то рекомендуется использовать умный указатель с подсчетом ссылок для переноса вашей дорогой структуры данных. boost::shared_ptr подходит для этой задачи, так как сделать копию этого довольно дешево.

0 голосов
/ 13 ноября 2009

Работает ли что-то подобное для вас?

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