Увеличить make_shared без аргумента шаблона
Я пытаюсь передать указатель на переменную стека в функцию (я не контролирую), которая принимает только boost::shared_ptr
,
Согласно этому ответу, используя boost::make_shared
это путь Чтобы проверить эту функциональность, я написал это:
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
int main(int argc, char const *argv[])
{
int i = 10;
boost::shared_ptr<int> int_ptr = boost::make_shared(i); // doesn't work
some_function(int_ptr); // this function takes only shared_ptr
return 0;
}
Но выдает следующую ошибку:
error: no matching function for call to ‘make_shared(int&)’
boost::shared_ptr<int> int_ptr = boost::make_shared(i);
^
Если я добавлю аргумент шаблона так, как он работает, но какова причина этого?
boost::shared_ptr<int> int_ptr = boost::make_shared<int>(i);
Спасибо!
2 ответа
Учитывая boost::make_shared<T>
шаблон:
namespace boost {
template<typename T, typename Arg1>
shared_ptr<T> make_shared( Arg1 const & arg1 );
}
Механизм шаблона может определить тип параметра. arg1
, Потому что он "видит" тип аргумента i
(который int
). Тем не менее, он не может вывести тип возвращаемого значения T
, Не знает тип T
из boost::shared_ptr<T>
вы будете назначать (т.е. он не имеет возможности узнать тип int_ptr
.)
boost::shared_ptr<T>
использует разные типы для аргумента (Arg1
) и вернуться (T
), чтобы позволить вам создавать общие указатели из аргументов, отличных от типа указателя. Например, double
в int
:
double d = 10.0;
std::shared_ptr<int> int_ptr = std::make_shared<int>(d);
Если вы хотите создать общие указатели, тип которых совпадает с аргументом, вы можете написать оболочку:
template<typename T>
boost::shared_ptr<T> my_make_shared(T const & arg) {
return boost::make_shared<T>(arg);
}
Но имейте в виду, что пока это работает
int i = 10.0;
std::shared_ptr<int> int_ptr = my_make_shared(i); // OK
Неявное преобразование типов не делает:
double d = 10.0;
std::shared_ptr<int> int_ptr = my_make_shared(d); // ERROR
Надеюсь, поможет!
Хотя в ответе Гильерме Феррейры подробно рассматривается вывод шаблонных аргументов (и в этом отношении он является правильным), я считаю, что это не тот ответ, который вы ищете.
Я пытаюсь передать указатель на переменную стека в функцию (я не контролирую), которая принимает только boost::shared_ptr.
shared_ptr
означает совместное владение указанным объектом. Если функция, которую вы пытаетесь вызвать, сохраняет указатель в некоторых своих структурах данных, например в контейнере, и затем возвращает его, указатель станет зависать, как только значение в стеке будет уничтожено, несмотря на то, что shared_ptr
все еще держит ссылку. Чтобы сделать то, что вы хотите, вы должны быть абсолютно уверены, что функция нигде не сохраняет указатель и может использовать его только во время этого одного вызова.
При условии, что это условие выполнено, вы можете создать shared_ptr
указывая на значение в стеке, но вы не можете использовать make_shared
для этого. make_shared
выделяет новый объект в куче вместе со счетчиком ссылок для него и инициализирует его аргументами, переданными в вызов функции. Возвращенный shared_ptr
указывает на этот новый объект, а не на объект в стеке.
void foo()
{
int n = 10;
boost::shared_ptr< int > pn = boost::make_shared< int >(n);
assert(*pn == 10); // succeeds
assert(pn.get() == &n); // fails
bar(pn);
}
Это подразумевает, что модификации bar
делает на острие int
не отражаются на n
,
Для того, чтобы создать shared_ptr
к существующему объекту, вы должны использовать его конструктор напрямую. Кроме того, поскольку время жизни объекта контролируется стеком, вы должны запретить shared_ptr
от уничтожения объекта. Это можно сделать, указав no-op delete shared_ptr
строительство.
void foo()
{
int n = 10;
boost::shared_ptr< int > pn(&n, boost::null_deleter());
assert(*pn == 10); // succeeds
assert(pn.get() == &n); // succeeds
bar(pn);
}
Обратите внимание, однако, что этот код по-прежнему выделяет кучу памяти для счетчика ссылок shared_ptr
использует, так что вы не выиграли ни одного представления.