#c #smart-pointers
Вопрос:
Рассмотрим следующий пример:
#include <iostream>
#include <memory>
struct A
{
explicit A(int x)
{
std::cout << x << std::endl;
}
};
void Foo(A ) {}
std::shared_ptr<A> Foo2(int x)
{
// why does this work?
return std::make_shared<A>(x);
}
int main()
{
A a(0);
Foo(a);
// Foo(1); does not compile
Foo2(2);
}
У меня есть a class A
с явным помеченным конструктором, чтобы он не преобразовывался из int
в class A
неявно. Но в вызове std::make_shared
я могу вызвать и создать этот класс, только передав an int
. Почему это возможно и есть ли что-то неправильное в том, как я это делаю?
Комментарии:
1. Ваши откровенны с
std::make_shared<A>
…2. Это было бы странным ограничением и непоследовательностью. Как бы вы тогда хотели создать
shared_ptr
дляA
использованияexplicit A(int x)
конструктора? Тогда единственным способом было бы писатьshared_ptr<A>(new A(0))
. Но еслиshared_ptr<A>(new A(0))
разрешено, то почемуstd::make_shared<A>(0)
не должно быть? Потомуmake_shared<A>
что предназначено для построенияA
на основе переданных аргументовmake_shared
?3. @Jarod42 Это, конечно, имеет смысл. Я думаю, что мое недопонимание здесь было вызвано тем, что я мог создать указатель на A без «ЯВНОГО» вызова конструктора. Но, конечно, тип хорошо известен, потому что я определяю его в шаблоне…
Ответ №1:
Это ожидаемое поведение, поскольку std::make_shared
выполняет прямую инициализацию, которая также учитывает явные конструкторы.
Объект строится так, как если бы выражение
::new (pv) T(std::forward<Args>(args)...)
Прямая инициализация более разрешительна, чем инициализация копирования: при инициализации копирования учитываются только неявные конструкторы и неявные определяемые пользователем функции преобразования, в то время как при прямой инициализации учитываются все конструкторы и все определяемые пользователем функции преобразования.
Foo(1);
не работает, потому что параметр инициализируется копированием, что не учитывает явные конструкторы.