const ref undefined behavior에 의해 새로 생성 된 객체를 캡처하고 있습니까?


11

다음 (확인 된 예)입니까, 아니면 정의되지 않은 동작입니까?

// undefined behavior?
const auto& c = SomeClass{};

// use c in code later
const auto& v = c.GetSomeVariable();

답변:


12

그것은 안전하다. Const ref는 일시적인 수명을 연장시킵니다. 범위는 const ref의 범위가됩니다.

임시 객체 의 수명 은 const lvalue 참조 또는 rvalue 참조 (C ++ 11부터)에 바인딩하여 확장 할 수 있습니다 . 자세한 내용 은 참조 초기화 를 참조하십시오.

참조가 임시 또는 하위 오브젝트에 바인드 될 때마다 다음 예외를 제외 하고 임시의 수명이 참조의 수명과 일치하도록 확장됩니다 .

  • return 문에서 함수의 반환 값에 대한 임시 바인딩은 확장되지 않으며 반환 식의 끝에서 즉시 삭제됩니다. 이러한 함수는 항상 매달려있는 참조를 반환합니다.
  • 생성자 이니셜 라이저 목록의 참조 멤버에 대한 임시 바인딩은 오브젝트가 존재하지 않는 한 생성자가 종료 될 때까지만 지속됩니다. (참고 : 이러한 초기화는 DR 1696부터 잘못 구성되어 있습니다).
  • 함수 호출에서 참조 매개 변수에 대한 임시 바인딩은 해당 함수 호출을 포함하는 전체 표현식이 끝날 때까지 존재합니다. 함수가 전체 표현식보다 오래 지속되는 참조를 리턴하면 매달려있는 참조가됩니다.
  • new-expression에 사용 된 이니셜 라이저의 참조에 대한 임시 바인딩은 초기화 된 객체가 아닌 한 해당 new-expression을 포함하는 전체 표현식이 끝날 때까지 존재합니다. 초기화 된 객체가 전체 표현식보다 오래 지속되면 해당 참조 멤버가 매달려있는 참조가됩니다.
  • 이니셜 라이저를 포함하는 전체 표현식의 끝까지 존재합니다. struct A { int&& r; }; A a1{7}; // OK, lifetime is extended A a2(7); // well-formed, but dangling reference

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

@Konrad 루돌프는 지적 (위의 마지막 단락 참조)

" c.GetSomeVariable()로컬 객체에 대한 참조 또는 자체적으로 일부 객체의 수명을 연장하는 참조를 반환하면 수명 연장이 시작되지 않습니다"


1
그 인용의 출처를 인용해야합니다.
궤도에서 가벼움 경주

@LightnessRaceswithMonica가 완료되었습니다. 더 나은 텍스트를 찾고있었습니다.
Oblivion

2
이것이 값에 대해서만 사실임을 강조하는 것이 좋습니다 . 경우 c.GetSomeVariable()리턴한다 참조 로컬 객체 또는 그 자체가 어떤 개체의 수명을 연장하는 것을 참조, 수명 연장은 않습니다 하지 킥.
콘라드 루돌프

@KonradRudolph 감사합니다! 나도 예외를 추가했다.
Oblivion

4

수명 연장 덕분에 여기에 문제가 없어야합니다 . 새로 생성 된 객체는 참조가 범위를 벗어날 때까지 유지됩니다.


3

예, 이것은 완벽하게 안전합니다. const참조에 대한 바인딩 은 임시의 수명을 해당 참조의 범위로 확장합니다.

그러나 동작은 전 이적 이지 않습니다 . 예를 들어

const auto& cc = []{
    const auto& c = SomeClass{};
    return c;
}();

cc 매달려 있습니다.


2

이것은 안전합니다.

[class.temporary]/5: 전체 표현 의 끝과 다른 지점에서 임시가 파괴되는 세 가지 컨텍스트가 있습니다 . [..]

[class.temporary]/6: 세 번째 컨텍스트는 참조가 임시 객체에 바인딩 된 경우입니다. 참조가 바인딩 된 임시 객체 또는 참조가 바인딩 된 하위 객체의 완전한 객체 인 임시 객체는 참조가 바인딩 된 glvalue가 다음 중 하나를 통해 얻은 경우 참조 수명 동안 지속됩니다. : [여기에 많은 것들]


1

이 특정한 경우에 안전합니다. 그러나 모든 임시가 const 참조로 캡처하는 것이 안전하지는 않습니다.

#include <stdio.h>

struct Foo {
    int member;

    Foo() : member(0) {
        printf("Constructor\n");
    }

    ~Foo() {
        printf("Destructor\n");
    }

    const Foo& method() const {
        return *this;
    }
};

int main() {
    {
        const Foo& x = Foo{};        // safe
        printf("here!\n");
    }
    {
        const int& y = Foo{}.member; // safe too (special rule for this)
        printf("here (2)!\n");
    }
    {
        const Foo& z = Foo{}.method(); // NOT safe
        printf("here (3)!\n");
    }
    return 0;
}

명령문 z에 도달하기 전에 전체 인스턴스의 끝에서 임시 인스턴스가 삭제되므로에 대한 참조 는 사용하기에 안전하지 않습니다 printf. 출력은 다음과 같습니다

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