2016-03-11 2 views
2

Я использую функцию C, которая имеет подпись как unique_ptr my_array с std::unique_ptr так, чтобы автоматически называться free? Я не могу изменить функцию C (которая является частью внешней библиотеки), поэтому я не могу изменить структуру данных, используемую в ней.обработку для двойного указателя

Существует similar question on SO, но в этом вопросе функция C вернула указатель, и вокруг этого возвращаемого значения было создано unique_ptr. Некоторые из предложенных ответов будет работать, если немой указатель был создан первым, а затем завернутые позже, например:

double * my_array; 
size_t array_length = load_array(source, &my_array); 
auto my_array_wrapper = std::unique_ptr<double, decltype(free)*>{ my_array, free }; 
// ... do stuff with my_array_wrapper ... 

// free() called on wrapped pointer when my_array_wrapper goes out of scope 

Это не кажется очень чистым для меня, так как я до сих пор оригинальный указатель валяется в моей код. То, что я хотел бы сделать, чтобы полностью содержать указатель, с чем-то вроде:

clever_ptr my_clever_array; 
size_t array_length = load_array(source, my_clever_array.get_ptr_address()); 
// ... do stuff with my_clever_array ... 

// free() called on wrapped pointer when wrapper goes out of scope 

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

+1

Вы можете, но почему бы вам просто не использовать вектор? –

+1

Возможно, он использует устаревший код C. Как показано выше, он принимает двойной указатель. –

+0

@ H.Guijt Функция C не использует векторные методы, поэтому я не вижу, как это будет работать. Я не могу изменить функцию C. – beldaz

ответ

1

Оказалось, что это невозможно сделать std::unique_ptr. Единственные способы получения на указатель из этого класса являются:

  • pointer get() const noexcept;, который, будучи const, не допустит значение управляемого указателя для изменения (возвращаемый указатель не const, но это копия управляющего, поэтому изменение его значения не изменит значение внутри unique_ptr)
  • pointer release() noexcept;, который освобождает право собственности на управляемый указатель и поэтому не будет называть free на нем, когда он выходит за рамки.

Следовательно, единственный маршрут заключается в том, чтобы обернуть указатель после его обновления. Для того, чтобы не оставлять указатель, лежащий вокруг него может быть помещен в блок, чтобы ограничить его объем:

std::unique_ptr<double, decltype(free)*> my_array_wrapper{nullptr, free}; 
{ 
    double * my_array; 
    size_t array_length = load_array(source, &my_array); 
    my_array_wrapper = std::unique_ptr<double, decltype(free)*>{ my_array, free }; 
} 
// ... do stuff with my_array_wrapper ... 
// free() called on wrapped pointer when wrapper goes out of scope 

Это, вероятно, может быть расширена с помощью обертки для load_array функции:

size_t load_array_wrapped(FILE * source, std::unique_ptr<double, decltype(free)*> & array_wrapper) { 
    double * my_array; 
    size_t array_length = load_array(source, &my_array); 
    my_array_wrapper = std::unique_ptr<double, decltype(free)*>{ my_array, free }; 
    return array_length; 
} 

, а затем вызвать с :

std::unique_ptr<double, decltype(free)*> my_array_wrapper{nullptr, free}; 
size_t array_length = load_array_wrapped(source, my_array_wrapper); 
+1

Вместо того, чтобы использовать блок, вы можете его обернуть в функцию, возможно, которая возвращает 'unique_ptr' и размер, и берет' source' как аргумент –

+1

Даже с этим решением вы должны нести длину отдельно по отдельности указатель, который не идеален; один подход к рассмотрению будет заключаться в создании пользовательского класса, который содержит указатель и длину (и не копируется и вызывает «free» в своем деструкторе, и вы можете предоставить контейнерные адаптеры) –

+0

@ M.M Спасибо. Я принял ваше предложение немного дальше и завернул в новую функцию, которая модифицирует 'unique_ptr' и возвращает длину. – beldaz