Я плохо понимаю, как умные указатели (особенно shared_ptr
) взаимодействуют с полиморфными типами. Общая картина кажется простой, но как только я начинаю разбираться в деталях, то просто тону в них.
Например, я не совсем уверен в том, что именно происходит "под капотом" в следующем коде:
shared_ptr<Base> get()
{
return make_shared<Derived>();
}
int main(int argc, char **argv)
{
shared_ptr<Base> base = get();
return 0;
}
Особенное непонимание вызывают ситуации, когда через указатель на базовый класс нужно попытаться достать объект производного класса (юнит-тесты и другие ситуации).
В случае с сырыми указателями или ссылками все тривиально:
void do_something(Base* base)
{
Derived *derived = dynamic_cast<Derived *>(base);
if (derived != nullptr)
{
// ...
}
}
Но в случае с умными указателями (особенно, разделяемыми shared_ptr
) все становится сложно, потому что это шаблонные классы, которые нековариантны.
Мне непонятно, чем отличается:
shared_ptr<Base> base = make_shared<Derived>();
И:
shared_ptr<Derived> base = make_shared<Derived>();
Также мне интересно, законно ли это, и есть ли тут потенциальные проблемы:
void do_something(shared_ptr<Base> base)
{
// Принято ли так делать?
Derived *derived = dynamic_cast<Derived *>(base.get());
if (derived != nullptr)
{
// ...
}
}
int main()
{
shared_ptr<Base> base = make_shared<Derived>();
do_something(base);
}
Умный указатель - это указатель, который умеет сам вызывать delete
объекту.
Отсюда сразу следует два свойства:
Если же говорить о том что с ним можно делать - ответ будет "смотри его интерфейс".
Конкретно в случае shared_ptr
вы можете делать с умным указателем почти всё что можно делать с указателем обычным: его можно копировать, приводить к указателю на базовый тип, также ему можно делать все 4 приведения типа через специальные функции (std::static_pointer_cast
, std::dynamic_pointer_cast
, std::const_pointer_cast
и std::reinterpret_pointer_cast
).
Также всегда можно получить сырой указатель через метод get()
, и далее делать с ним что угодно кроме вызова delete. Но так поступать не рекомендуется: если вы широко используете умные указатели, то сырой указатель можно случайно "обернуть" в умный, что приведет к вызову delete.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Для наглядности: на вход программе даётся число, к примеру 1234Нужно сделать так, чтобы на выходе вывелось число 4321
Мне надо зафиксировать элемент в конце первой строки во flex-контейнере (который имеет flex-wrap: wrap)См