std :: unique_ptr и указатель на указатель - PullRequest
8 голосов
/ 19 декабря 2010

Я использовал std :: unique_ptr для хранения некоторых COM-ресурсов и предоставил пользовательскую функцию удаления. Тем не менее, многие функции COM хотят указатель-указатель. Прямо сейчас я использую детали реализации _Myptr в моем компиляторе. Собирается ли сломать unique_ptr для прямого доступа к этому элементу данных, или я должен хранить временные указатели gajillion для построения значений unique_ptr из?

Ответы [ 4 ]

6 голосов
/ 17 февраля 2011

COM-объекты по своей природе являются подсчитываемыми ссылками, поэтому вы не должны использовать ничего, кроме умных указателей подсчета ссылок, таких как ATL::CComPtr или _com_ptr_t, даже если это кажется неподходящим для вашего варианта использования (я полностью понимаю ваши опасения, я просто думаю, что вы назначаете им слишком большой вес). Оба класса предназначены для использования во всех допустимых сценариях, возникающих при использовании объектов COM, включая получение указателя на указатель. Да, это слишком большая функциональность, но если вы не ожидаете каких-либо конкретных негативных последствий, которые вы не можете терпеть, вы должны просто использовать эти классы - они предназначены именно для этой цели.

4 голосов
/ 03 марта 2011

Мне пришлось решать эту проблему не так давно, и я предложил два разных решения:

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

Поэтому я не придерживался этого.Так что я сделал вспомогательную функцию Retrieve, которая получала бы функцию COM и возвращала бы мой smart-указатель (и выполнял всю работу с временным указателем внутри).Теперь это тривиально работает со свободными функциями, которые имеют только один параметр T**.Если вы хотите использовать это для чего-то более сложного, вы можете просто передать вызов через std::bind и оставить только указатель, который будет возвращен, свободным.

Я знаю, что это не то, что выВы спрашиваете, но я думаю, что это аккуратное решение вашей проблемы.

В качестве примечания, я бы предпочел повысить intrusive_ptr в Boost вместо std :: unique_ptr, но это дело вкуса,как всегда.

Редактировать: Вот пример кода, который был перенесен из моей версии с использованием boost :: intrusive_ptr (поэтому он может не работать "из коробки" с unique_ptr)

template <class T, class PtrType, class PtrDel>
HRESULT retrieve(T func, std::unique_ptr<PtrType, PtrDel>& ptr)
{
  ElementType* raw_ptr=nullptr;

  HRESULT result = func(&raw_ptr);
  ptr.reset(raw_ptr);

  return result;
}

Например, его можно использовать так:

std::unique_ptr<IFileDialog, ComDeleter> FileDialog;
/*...*/
using std::bind;
using namespace std::placeholders;
std::unique_ptr<IShellItem, ComDeleter> ShellItem;
HRESULT status = retrieve(bind(&IFileDialog::GetResult, FileDialog, _1), ShellItem);

Для бонусных баллов вы можете даже позволить retrieve вернуть unique_ptr вместо того, чтобы брать его по ссылке.Функтор, который генерирует bind, должен иметь сигнатуры typedef для получения типа указателя.Затем вы можете сгенерировать исключение, если получите плохой HRESULT.

1 голос
/ 03 марта 2011
Умные указатели

C ++ 0x имеют переносимый способ получить контейнер необработанных указателей .get () или полностью освободить его с помощью .release ().Вы также можете всегда использовать & (* ptr), но это менее идиоматично.

Если вы хотите использовать умные указатели для управления временем жизни объекта, но все еще нужны необработанные указатели для использования библиотеки, которая неПоддерживая умные указатели (включая стандартную библиотеку c), вы можете использовать эти функции для наиболее удобного доступа к необработанным указателям.

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

Что-то вроде:

call_com_function( &my_uniq_ptr.get() ); // will work fine
return &my_localscope_uniq_ptr.get();    // will not
return &my_member_uniq_ptr.get();        // might, if *this will be around for the duration, etc..

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

0 голосов
/ 25 марта 2013

Используйте вспомогательную функцию, подобную этой.

template< class T >
T*& getPointerRef ( std::unique_ptr<T> & ptr )
{
    struct Twin : public std::unique_ptr<T>::_Mybase {};
    Twin * twin = (Twin*)( &ptr );
    return twin->_Myptr;
}

проверьте реализацию

int wmain ( int argc, wchar_t argv[] )
{   
    std::unique_ptr<char> charPtr ( new char[25] );
    delete getPointerRef(charPtr);
    getPointerRef(charPtr) = 0;

    return charPtr.get() != 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...