Константный параметр ссылочной функции: можно ли запретить временные объекты?

Возможно иметь параметр функции, который обеспечивает следующую семантику:

Параметр не будет изменен функцией. Вызов функции никогда не создает копию или временный объект для параметра.

Пример:

void f(const std::string & str);

Интерфейс сообщает клиентам, что параметр не будет изменен, и если параметр уже имеет тип std::string, копия не создается.

Но это все еще можно назвать

const char * hello = "hello";
f(hello);

который создает временный объект std::string перед входом в функцию f и снова уничтожает его после выхода из f.

Можно ли запретить это либо с помощью другого объявления функции, либо (гипотетически) изменив реализацию std::string.


person Ludwig Schulze    schedule 07.05.2018    source источник
comment
Звучит как проблема XY для меня. Одной из прелестей языка является автоматическое временное создание и связывание. Почему вы хотите это запретить? Если вы заботитесь о возможном снижении производительности из-за вызова конструктора, это должна быть не проблема поставщика API, а проблема вызывающей стороны. Практическим решением для std::string является использование std::string_view или домашнего решения.   -  person SergeyA    schedule 07.05.2018
comment
Пришлось искать, что означает xy-проблема. Нет я так не думаю. Согласитесь, это будет ответственность клиента. Но это тоже я, и мне любопытно, смогу ли я убедиться, что не ошибаюсь в своих звонках. И std::string здесь просто используется в качестве примера. Не особо интересует std::string. Приятно, что я узнал кое-что новое о =delete.   -  person Ludwig Schulze    schedule 09.05.2018


Ответы (1)


Я собираюсь начать с конца здесь.

или (гипотетически) изменив std::string реализацию

Не делайте этого, опасаясь носовых демонов. Серьезно, не надо. Пусть стандартная библиотека ведет себя стандартным образом.

Можно ли запретить это либо с помощью другого объявления функции

По сути, еще одна декларация — это всего лишь билет. Добавьте перегрузку, которая принимает ссылку на значение r, и определите ее как удаленную:

void f(std::string && str) = delete;

Разрешение перегрузки выберет его как временное, а удаленное определение вызовет ошибку. Ваша предполагаемая функция теперь может быть вызвана только с l-значениями.

person StoryTeller - Unslander Monica    schedule 07.05.2018
comment
std::string — это просто всем известный пример, и я согласен, что не хочу его менять. Интересно с ключевым словом delete, надо попробовать. Я знал только об удалении конструкторов по умолчанию и т.п. таким образом. - person Ludwig Schulze; 07.05.2018
comment
@LudwigSchulze - вы можете указать удаленное определение для любой функции. Гораздо проще заставить разрешение перегрузки подняться, когда вы хотите что-то предотвратить :) - person StoryTeller - Unslander Monica; 07.05.2018
comment
Я чувствую, что после того, как я попробовал это, у меня может возникнуть дополнительный вопрос для случаев с ~ 5 параметрами, где ~ 3 параметра имеют эту семантику. Будет новый вопрос, конечно. - person Ludwig Schulze; 07.05.2018