Возможность изпользовать std::make_shared с приватными конструкторами и фабричными методами

fgenatre
fgenatre

std::make_shared<>() имеет ряд преимуществ перед обычным конструированием std::shared_ptr - к примеру, память и выделяется за один раз, а не за два (согласно рекомендации в стандарте),  и сам объект и счетчик ссылок на него распалагаются в куче рядом (что в некоторых случаях может дать небольшой плюс в плане оптимизации).
В нынешнем виде std::make_shared<>() не позволяет конструировать объекты с приватным конструктором даже при вызове из подходящего контекста (разве что только с некоторыми ухищрениями, типа наследования пустого производного класса и создания его экземпляра или объявлении вызываемой функции как friend для создаваемого класса).
Между тем,  на текущий момент не видно каких-либо серьезных преград разрешить использование std::make_shared<>() для объектов с приватными конструкторами - компилятору понадобится просто определить допустимость подобной операции в зависимости от контекста вызова (как сейчас при обычном создании shared_ptr).

Бонусом можно еще разрешить использовать make_shared<>() с фабричными методами, возвращающими сырой указатель (типа SomeObject* SomeObject::create(), например при использовании сторонних библиотек) - только там заранее неизвестно какой объект вернется (может быть сконструирован объект одного из унаследованных классов), следовательно, заранее память не аллоцируешь, и  как вариант, компилятор может генерировать вариант фабричного метода, в котором вместо 'new' будет вызываться make_shared, и сконструированный умный указатель будет передаваться в вызываюшую функцию

Плюсы: упрощение кода и улучшение читаемости.

-3
рейтинг
6 комментариев
Павел Корозевцев
На данный момент, если написать make_shared<C> (где C -- класс с приватным конструктором), мы получим от компилятора стек из восьми функций (на моей версии libstdc++), вызываемых внутри make_shared. Верхняя функция -- __gnu_cxx::new_allocator<C>::construct. Должно ли быть у неё разрешение на вызов приватного конструктора C? А у остальных семи промежуточных функций?

Как ваше предложение могло бы быть реализованно в стандарте и в компиляторах? Мне абсолютно не понятен механизм :(
Павел Корозевцев
Antervis
можно добавить специализацию make_shared как friend
Antervis
yndx-antoshkka
Antervis, не поможет. Нужно ещё добавить allocate_shared и возможно какие-то внутренности конкретной имплементации стандартной библиотеки.
yndx-antoshkka
dmitriy@izvolov.ru
Можно просто сконструировать объект снаружи и засунуть его как rvalue в make_shared. В C++17 при этом не должно произойти ни копирования, ни переноса.
dmitriy@izvolov.ru
yndx-antoshkka
dmitriy@izvolov.ru, вы подняли очень интересную тему! В данный момент так не работает godbolt.org/g/V3edfK . Если сделать чтобы работало - будет ооочень круто, rvalue будут более легковесными и будут работать с copy elision.

Однако это поменяет порядок следования вызовов. И может быть неприятно в ряде случаев. Я обдумаю и обсужу с разработчиками компиляторов.
yndx-antoshkka
dmitriy@izvolov.ru
yndx-antoshkka, действительно, как-то я слишком оптимистично отнёсся к "copy elision". Но с интересом жду результатов обдумывания и обсуждения.
dmitriy@izvolov.ru
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).