2009-11-13 6 views
5

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

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

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

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 данных). Однако это приводит к небольшой утечке памяти (структура данных для обработки емкости, размера и т. Д., Но не самих данных).

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

+0

Это довольно запутанно. Также попробуйте спросить на форуме C++. – Nzbuu

+0

mxSetData и mxArray являются частью интерфейса Matlab C (через файлы C mex). – spirov

+0

Да, но это не вопрос Matlab * - Люди, знающие, что Matlab придет сюда, чтобы помочь вам, не смогут вносить что-либо, если они не знают C++. – quark

ответ

0

Что-то вроде этого работает для вас?

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

Простое решение будет обменивать вектор с одной вы владеете:

vector<double> myown; 

vector<double> someoneelses = foo(); 

std::swap(myown, someoneelses); 

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

+0

Простой, «чистый» и очень эффективный с точки зрения перспективы. myown может быть создан на куче или где-то в другом месте, чтобы жить после того, как кто-то выходит из сферы действия. –

+1

или даже короче: 'foo(). Swap (myown);' – sellibitze

+0

Спасибо за указание пользовательских распределителей. Я унаследовал распределитель в allocator_derived с пользовательским поведением (будьте осторожны, чтобы не удалять, если какой-либо флаг установлен пользователем, то есть непосредственно перед выпуском вектора). Это отлично работает и не течет с некоторой осторожностью ... на некоторых системах, но не для всех, к сожалению. Например, он работает на mac (gcc 4.2.1), но на 64-битном Linux (gcc 4.3), вектор, объявленный как вектор >, даже не использует производное поведение; Я не знаю, почему. – spirov

1

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

5

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

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

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

+1

+1 для обозначения конструкции '& v [0]' для совместимости с C-подобным интерфейсом. –

+0

Третий элемент является ключевым, поскольку передача содержимого вектора внешним функциям без копирования является большой частью того, чего хочет OP. – quark

-2

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

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

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

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

Смежные вопросы