Можно ли вернуть значение аргумента по умолчанию с помощью константной ссылки? - PullRequest
25 голосов
/ 01 ноября 2019

Можно ли возвращать значение аргумента по умолчанию с помощью константной ссылки, как в следующих примерах:

https://coliru.stacked -crooked.com / a / ff76e060a007723b

#include <string>

const std::string& foo(const std::string& s = std::string(""))
{
    return s;
}

int main()
{
    const std::string& s1 = foo();
    std::string s2 = foo();

    const std::string& s3 = foo("s");
    std::string s4 = foo("s");
}

Ответы [ 3 ]

17 голосов
/ 01 ноября 2019

В вашем коде и s1, и s3 являются висячими ссылками. s2 и s4 в порядке.

При первом вызове временный пустой объект std::string, созданный из аргумента по умолчанию, будет создан в контексте выражения, содержащего вызов. Следовательно, он умрет в конце определения s1, что оставляет s1 свисающим.

Во втором вызове временный объект std::string используется для инициализации s2, затем онУмирает.

В третьем вызове строковый литерал "s" используется для создания временного объекта std::string, который также умирает в конце определения s3, оставляя s3 висящим.

В четвертом вызове временный объект std::string со значением "s" используется для инициализации s4, а затем он умирает.

См. C ++ 17 [class.teven]/6.1

Временный объект, связанный с опорным параметром в вызове функции (8.2.2), сохраняется до завершения полного выражения, содержащего вызов.

8 голосов
/ 01 ноября 2019

Это небезопасно :

Как правило, срок службы временного элемента не может быть дополнительно продлен путем «передачи его»: вторая ссылка, инициализированная из ссылкик которому был привязан временный, не влияет на его время жизни.

5 голосов
/ 01 ноября 2019

Это зависит от того, что вы будете делать со строкой впоследствии.

Если ваш вопрос , мой код правильный? , тогда да, это так.

С [dcl.fct.default] / 2

[ Пример : Объявление

void point(int = 3, int = 4);

объявляет функцию, которая может быть вызвана с нуля, один или два аргумента типа int. Его можно вызвать любым из следующих способов:

point(1,2);  point(1);  point();

Последние два вызова эквивалентны point(1,4) и point(3,4) соответственно. - конец примера ]

Таким образом, ваш код фактически эквивалентен:

const std::string& s1 = foo(std::string(""));
std::string s2 = foo(std::string(""));

Весь ваш код верен, но в ссылочном продлении срока службы нетв любом из этих случаев, поскольку возвращаемый тип является ссылкой.

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

const std::string& s1 = foo(std::string("")); // okay

s1; // not okay, s1 is dead. s1 is the temporary.

Ваш пример с s2 в порядке, так как вы копируете (или перемещаете) из временного хранилища до окончания периода исполнения. s3 имеет ту же проблему, что и s1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...