Использование shared_ptr в качестве выходного параметра - PullRequest
4 голосов
/ 16 февраля 2012

Я работаю над C ++ API, который экспортирует несколько классов из DLL.

Интерфейс открытого класса должен соответствовать следующим соглашениям:

  • Все функции возвращают код ошибки.
  • Выходные параметры используются для дополнительных возвращаемых значений.
  • Передача по указателю используется для выходных параметров.
  • Передача по константной ссылке используется для входных параметров (передача по значению для примитивных типов).
  • Когда клиент должен стать владельцем выходного параметра, используется shared_ptr, в противном случае - обычный указатель.

Пример интерфейса:

typedef std::shared_ptr<Object> ObjectPtr;

class APIClass
{
    ErrorCode SetSomething(int i);
    ErrorCode IsSomethingSet(bool* ask);
    ErrorCode DoSomething();
    ErrorCode GetSomething(ObjectPtr* outObj);
}

Пример использования:

ErrorCode res;
ObjectPtr obj;
res = myApiClass->GetSomething(&obj);

Реализация GetSomething:

ErrorCode APIClass::GetSomething(ObjectPtr* outObj)
{
   ObjectPtr temp(new Object(), CleanUpFunction<Object>);

   // Do something with object temp.
   ...

   *outObj= temp;

   return OK;
}

Безопасно ли использовать shared_ptr таким образом или есть возможные проблемы, о которых мне следует знать?

1 Ответ

1 голос
/ 17 февраля 2012

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

Обычно я документирую функцию и использую что-то вроде:

// Caller must delete the outObj once done.
ErrorCode APIClass::GetSomething( Object* & outObj )
{
  // I use auto_ptr so I can release it later...
  // Mostly I hate auto_ptr, but for this its invaluable.

  auto_ptr<Object> obj( new Object );
  ...
  outObj = obj.release();
  return OK;
}

Таким образом, это зависит от клиентаЯ хочу сохранить указатель в, и ясно, что право собственности на объект переходит к вызывающей стороне.

Клиентский код может затем использовать соответствующий контейнер.

Object * obj_raw;
ErrorCode ec = apiClass.GetSomething( obj_raw )
if( ec!=OK ) { .. do something with ec .. }
shared_ptr<Object> obj( obj_raw );

или

auto_ptr<Object> obj( obj_raw );

или

scoped_ptr<Object> obj( obj_raw); 

и т. Д.

Обратите внимание, что это можно сделать более аккуратно, если изменить определение функции на:

// Caller must delete the return value.
// On error, NULL is returned and e filled in appropriately.
Object* APIClass::GetSomething( ErrorCode & e )
{
   auto_ptr<Object> obj( new Object );
   ..
   e = OK;
   return obj.release();
}

//Now using it looks like this:
ErrorCode ec;
shared_ptr<Object> obj( apiObject.GetSomething(ec) ); 
if(!obj)
{
   .. do something with ec ..
}
...