Рассмотрим следующий код:
#include <iostream>
#include <memory>
class Test
{
public:
Test(int t) : t(t) {}
int t;
};
void test(std::shared_ptr<Test> t)
{
std::cout << t.use_count() << std::endl;
}
int main()
{
auto t = std::make_shared<Test>(1);
test(std::move(t)); //(1)
test(std::make_shared<Test>(2)); //(2)
}
Вопросы:
t
в void test(std::shared_ptr<Test> t)
, а затем временный объект уничтожается. Это верно?Важно отметить, что перемещение (в обоих случаях) и временное (в случае 2) — это сам объект std::shared_ptr<Test>
, а не объект Test
, на который он переносит указатель. В каждом случае будет только один объект Test
, который не перемещается и не копируется.
Подтвердите 1, проверив t
и use_count
в конце main.
Всего в вашем примере создано 3 std::shared_ptr<Test>
:
auto t = std::make_shared<Test>(1);
test(std::move(t));
- Прием t
в test()
построен на ходу.
test(std::make_shared<Test>(2));
— Получающий t
— это тот, который создан make_shared()
. Это тот же объект из-за обязательного копирования/перемещения, начиная с C++17.
До C++17 теоретически можно было получить до 5 экземпляров, но поскольку такой тип исключения был разрешен (но не обязателен) в предыдущей версии, в этих версиях вы, скорее всего, получите только 3. При использовании одной из этих более ранних версий вы можете отключить эту оптимизацию в некоторых компиляторах (например, g++
/clang++
) с помощью -fno-elide-constructors
. В C++17 и более поздних версиях исключение является обязательным и поэтому его нельзя отключить.
Вот демо, в котором используется не shared_ptr
, а тестовый класс под названием foo
, чтобы вы могли отслеживать каждое создание экземпляра. Обратите внимание, что существует только один foo
со значением 2
, который соответствует вашему вызову test(std::make_shared<Test>(2));
.
Вы имеете в виду, что если -fno-elide-constructors
используется, например, с компилятором C++11, то в случае (2) в моем примере принимающий t
будет создан с помощью Move ctor?
@cppdev Да (пример, где у gcc есть конструкторы no-elide-constructors, а у clang нет), и обратите внимание, что auto t = std::make_shared<Test>(1);
(auto t = make_foo(1);
) также приводит к конструкции перемещения, когда эта опция используется, поэтому всего существует 5 экземпляров.
в обоих случаях используется конструктор перемещения (хотя во втором случае его можно опустить): godbolt.org/z/bf1ohrvxW