передача умного указателя на функцию, ссылающуюся на параметр указателя

Как передать smart ptr функции, использующей указатель в качестве параметра?

smart_ptr<T> val; // I have this smart pointer

// And I want to pass it to this function, so that this function will fill the smart pointer with proper value
void Foo(T*& sth)
{
    sth = memoryAddress;
}

ИЗМЕНИТЬ Теперь я понял. Спасибо, ребята, за все ответы!


person user2032932    schedule 23.07.2013    source источник
comment
Возможно, вы имели в виду: shared_ptr?   -  person avakar    schedule 23.07.2013


Ответы (3)


Ответ прост: вы не можете. Хотя интеллектуальный указатель почти наверняка содержит T* где-то внутри, интеллектуальные указатели применяют всевозможные инварианты, многие из которых могут быть нарушены, если вы можете изменить этот указатель без прохождения через пользовательский интерфейс. Единственное решение - вызвать функцию с необработанным указателем, а затем использовать необработанный указатель для инициализации интеллектуального указателя, при условии, что вы уверены, что полученный указатель соответствует требованиям интеллектуального указателя. (например, выделено оператором new).

person James Kanze    schedule 23.07.2013

Ух, этот API уродливый.

Я предполагаю, что функция обещает, что указатель, который она «возвращает», владеет ресурсом, который должен быть удален вызывающей стороной так же, как это делает smart_ptr, и что smart_ptr может быть инициализирован с помощью произвольного указателя. Иначе и быть не может.

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

T* ptr;
Foo(ptr);
smart_ptr<T> val(ptr);

Может случиться так, что интеллектуальный указатель уже чем-то владеет, и вы хотите передать это что-то функции, а затем заменить то, чем владеет интеллектуальный указатель. Это ... даже уродливее.

Я не знаю, перейдет ли функция во владение переданным вами ресурсом (обычно я этого не ожидал, но поскольку API такой уродливый, я не собираюсь клясться им). Это приводит к двум различным сценариям.

Если функция становится владельцем переданного вами ресурса, т.е. она заботится об удалении самого указателя, тип интеллектуального указателя должен быть таким, который может отказаться от владения ресурсом, например std::unique_ptr с функцией-членом release(). Примечательно, что std::shared_ptr не может этого делать (учтите, что другие shared_ptr также могут владеть им).

Итак, предполагая, что интеллектуальный указатель имеет такую ​​возможность и возможность повторно инициализировать произвольный указатель (например, с std::unique_ptr::reset), вы можете сделать следующее:

//smart_ptr<T> val;
T* ptr = val.release();
Foo(ptr);
val.reset(ptr);

Если функция не получает права владения ресурсом, все, что требуется, - это возможность повторной инициализации с произвольным указателем.

//smart_ptr<T> val;
T* ptr = val.get();
Foo(ptr);
val.reset(ptr);
person R. Martinho Fernandes    schedule 23.07.2013
comment
Я хотел бы сначала убедиться, что возвращаемый указатель соответствует требованиям интеллектуального указателя. Тот, кто способен спроектировать такой сломанный интерфейс, также способен использовать malloc. - person James Kanze; 23.07.2013
comment
@James: да, это первое предположение во втором абзаце. - person R. Martinho Fernandes; 23.07.2013
comment
Я понимаю. Замечание о том, что функция делает с параметром во входе, тоже хорошее. Обычно такие функции ничего не делают, но как знать. - person James Kanze; 23.07.2013

Вы не можете этого сделать. Вы можете передать необработанный указатель, используя «T* raw = val.get()», затем «Foo(raw)», но вы не можете установить необработанный указатель shared_ptr внутри Foo. Если вы хотите, чтобы Foo установил shared_ptr, сделайте так, чтобы он принимал неконстантную ссылку shared_ptr.

Нравится:

template<typename T>
Foo(shared_ptr<T>& ptr)
{
    ptr.reset(memoryAddress); // Or assign it, or make_shared, or whatever.
}

shared_ptr<int> intptr;
Foo(intptr);

Или еще лучше, заставьте Foo возвращать shared_ptr, а не брать его по ссылке.

person Ben Hymers    schedule 23.07.2013
comment
Foo( val.get() ) не должен компилироваться. Если это так, ваш компилятор сломан. - person James Kanze; 23.07.2013
comment
Ты прав. Это работает, если вы переходите через временный. Я обновлю свой ответ. - person Ben Hymers; 23.07.2013
comment
Если он может изменить интерфейс на Foo, он может сделать это правильно и Foo _return` указатель. - person James Kanze; 23.07.2013
comment
Что я и сказал :) - person Ben Hymers; 23.07.2013