Игнорирует ли make_shared явный спецификатор?

#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); не работает, потому что параметр инициализируется копированием, что не учитывает явные конструкторы.