const 참조로 기본 인수 값을 반환해도됩니까?


26

아래 예제와 같이 const 참조로 기본 인수 값을 반환해도됩니까?

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
간단한 테스트 : std::string자신 만의 클래스로 교체 하여 구성 및 파괴를 추적 할 수 있습니다.
user4581301

1
@ user4581301 시퀀스가 ​​정확하다면 구문이 정상임을 증명하지 못합니다.
피터-모니카 복원 복원

6
@ user4581301 정의되지 않은 행동에 대해 절대 최악의 일이 "나는 시도 할 때 그것은 일에 등장"
HerrJoebob

문제는 말로 오해의 소지가 있다는 점에 유의해야합니다. const 참조로 기본 인수의 값을 반환하지는 않지만 const 참조 (...를 기본 인수로)에 대한 const 참조를 반환합니다.
데이먼

2
@HerrJoebob 100 % 문장에 동의하지만 사용하는 컨텍스트가 아닙니다.이 질문을 읽는 방식은 "오브젝트의 수명이 언제 끝났습니까?" 소멸자가 언제 호출되는지 알아내는 것이 좋은 방법입니다. 자동 변수의 경우 소멸자가 적시에 호출되어야하거나 큰 문제가 있습니다.
user4581301 2018

답변:


18

코드에서 두 s1s3참조 매달려있다. s2그리고 s4괜찮습니다.

첫 번째 호출 std::string에서 기본 인수에서 작성된 임시 빈 오브젝트는 호출을 포함하는 표현식의 컨텍스트에서 작성됩니다. 따라서, 정의의 끝에서 죽을 s1잎, s1댕글.

두 번째 호출에서 임시 std::string객체는 초기화 s2에 사용 된 다음 죽습니다.

세 번째 호출에서 문자열 리터럴은 "s"임시 만드는 데 사용되는 std::string개체를 그 또한 정의의 끝에서 사망 s3떠나 s3매달려 있습니다.

네 번째 호출에서는 std::string"s"이 있는 임시 개체를 사용하여 초기화 s4한 다음 죽습니다.

C ++ 17 [class.temporary] /6.1 참조

함수 호출 (8.2.2)에서 참조 매개 변수에 바인드 된 임시 오브젝트는 호출을 포함하는 전체 표현식이 완료 될 때까지 지속됩니다.


1
답의 흥미로운 부분은 기본 인수가 호출자의 컨텍스트에서 작성 될 것이라는 주장입니다. 그것은 기 illa의 표준 인용문에 의해 뒷받침되는 것 같습니다.
피터-복원 모니카

2
@ Peter-ReinstateMonica [expr.call] / 4, "... 각 매개 변수의 초기화 및 제거는 호출 함수의 컨텍스트 내에서 발생합니다. ..."
Brian

8

그것은이다 안전하지 :

일반적으로 임시의 수명은 "통과"하여 연장 할 수 없습니다. 임시가 바인딩 된 참조에서 초기화 된 두 번째 참조는 수명에 영향을 미치지 않습니다.


그렇다면 당신 std::string s2 = foo();은 타당 하다고 생각합니까 (결국에는 명시 적으로 참조가 전달되지 않습니다)?
피터-복원 모니카

1
@ Peter-ReinstateMonica 새로운 객체가 생성 될 때 안전한 것입니다. 내 대답은 단지 평생 확장에 관한 것입니다. 다른 두 가지 답변은 이미 모든 것을 다루었습니다. 나는 반복하지 않을 것이다.
Oblivion

5

나중에 문자열로 무엇을하는지에 따라 다릅니다.

귀하의 질문이 내 코드가 맞다면?그렇다면 그렇습니다.

가입일 [dcl.fct.default / 2

[ : 선언

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

int 유형의 0, 1 또는 2 개의 인수로 호출 할 수있는 함수를 선언합니다. 다음과 같은 방법으로 호출 할 수 있습니다.

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예포가 끝나기 전에 일시적으로 복사하거나 이동하기 때문에 with 가 포함 된 예 는 괜찮습니다. s3와 같은 문제가 s1있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.