2012-07-31 3 views
5
struct A { 
    A(int) : i(new int(783)) { 
     std::cout << "a ctor" << std::endl; 
    } 

    A(const A& other) : i(new int(*(other.i))) { 
     std::cout << "a copy ctor" << std::endl; 
    } 

    ~A() { 
     std::cout << "a dtor" << std::endl; 
     delete i; 
    } 

    void get() { 
     std::cout << *i << std::endl; 
    } 

private: 
    int* i; 
}; 

const A& foo() { 
    return A(32); 
} 

const A& foo_2() { 
    return 6; 
} 

int main() 
{ 
    A a = foo(); 
    a.get(); 
} 

로컬 값에 대한 참조를 반환하는 것이 좋습니다. 그러나 다른 한편으로, const 참조는 임시 객체 수명을 연장해야합니다.const 참조를 로컬 객체로 반환 할 때 정확히 무엇이 발생합니까?

이 코드는 UB 출력을 생성합니다. 그래서 인생 연장은 없습니다.

왜? 누군가가 단계적으로 일어나는 일을 설명 할 수 있습니까?

내 추론 연쇄에 결함이 있습니까?

foo는()

  1. A (32) -의 ctor

  2. 복귀 A (32) - 로컬 객체에 const를 참조하여 생성되며

  3. A A를 반환 = foo(); - a는 foo() 반환 값으로 초기화되고, 반환 값은 범위를 벗어나 (표현에서 벗어남) 파기되지만 a는 이미 초기화되었습니다.

(그러나 실제로 소멸자는 복사 생성자 전에 호출됩니다)

FOO_2() :

  1. 반환 6 - A 형의 임시 객체는이 객체에, 암시 적으로 const를 참조를 생성 창조되고 (생명 연장) 돌려 보내진다.

  2. A = foo(); - a는 foo() 반환 값으로 초기화되고, 반환 값은 범위를 벗어나 (표현에서 벗어남) 파기되지만 a는 이미 초기화되었습니다. 각각의 특정 상황에 맞는 임시 수명 연장의

(그러나 실제로 소멸자가 복사 생성자 전에 호출됩니다)

+1

"const 참조는 임시 객체 수명을 연장해야합니다."<- erm, 아니요. object-lifetime이 아닌 const 및 const 참조가 동일하고 확장하지 않습니다 * 확장하지 않습니다. – Giel

+2

알렉산더가 평생 동안 연장 할 수 있다고 생각하는 것 같습니다 : http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-most-important-const/ – vmpstr

+1

@Giel : No. Const reference ** **는 임시 객체의 수명을 연장 할 수 있습니다. const와 non-const 참조는 임시 변수로 작업 할 때 상당히 다릅니다. 이 경우에는 OP가 기대하는 것과 다르게 작동합니다. – AnT

답변

11

규칙은 명시 적으로 언어 사양에서 철자. 그리고 그것은 참조가 임시로 결합 될 때

12.2 임시 객체

5 번째 상황이라고 말했다. [...] 함수 반환 문 (6.6.3)의 반환 값에 대한 임시 바인딩은 함수가 종료 될 때까지 유지됩니다. [...]

임시 개체는 기능 종료 순간에 소멸됩니다. 이는 수신자 객체의 초기화가 시작되기 전에 발생합니다.

당신은 임시가 어쨌든 그보다 오래 살아야한다고 생각하는 것 같습니다. 분명히 임시는 전체 표현의 끝까지 살아남 아야한다는 규칙을 적용하려고합니다. 그러나이 규칙은 함수 내부에서 생성 된 임시 변수에는 적용되지 않습니다. 그러한 일시적인 자들의 생애는 그들 자신의 헌신적 인 규칙들에 의해 지배된다.

누군가 foofoo_2 모두 누군가가 반환 된 참조를 사용하려고하면 정의되지 않은 동작을합니다.

+0

"함수 반환 문 (6.6.3)에서 반환 된 값에 대한 임시 바인딩은 함수가"foo_3() {return A (54);}에서 초기화되기 전에 "임시 값이 소멸 될 때까지 계속 유지됩니까? – Alexander

+1

@Alexander - 아니요,'A foo_3()'은 값의 복사본을 반환합니다. 복사 된 값은 함수의 끝에서 소멸되지 않습니다. 참조를 반환 할 때 참조는 여전히 존재합니다. 이제 더 이상 참조를 참조하지 않습니다. –

+0

나는 ..하지만 복사 ctor는 식에서 2 번 호출해야한다. A a = foo_3(); 임시 반환 값을 복사 할 때 첫 번째로 A와 A를 초기화 할 때 두 번째로 복사합니다. 하지만 한 번만 불렀습니다. 아니면 그냥 최적화? – Alexander

3

"함수 종료까지"오보가 있습니다. 당신이 정말로 foo 넘어 개체의 수명을 연장하기 위해 const를 참조를 사용하려면, 경우, 반환 값을 참조하는 값에 의해 foo에서 반환해야

A foo() { 
    return A(32); 
} 
int main() { 
    const A& a = foo(); 
} 

를 사용하여 다음 CONST 참조를 사용 당신은 당신이 기대하는대로 물건을 확장하고자합니다.

@AndreyT가 말했듯이, 객체는 const & 인 함수에서 소멸됩니다. 당신은 당신의 객체가 foo 이상 생존 할, 따라서 당신이 해야하지이 어디 foo 또는 foo의 반환 형식에 const & (또는 &). const &의 첫 번째 언급은 객체를 유지해야하는 함수이기 때문에 main에 있어야합니다.

반품시 A 사본이있는 것처럼 보이기 때문에이 반품 코드가 느린 것으로 생각할 수 있지만 올바르지 않습니다. 대부분의 경우 컴파일러는 마지막 위치 (즉, 호출 함수의 스택)에 A를 한 번만 구성한 다음 관련 참조를 설정할 수 있습니다.

관련 문제