태그 보관물: c++11

c++11

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

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

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

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



답변

그것은 안전하다. 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()로컬 객체에 대한 참조 또는 자체적으로 일부 객체의 수명을 연장하는 참조를 반환하면 수명 연장이 시작되지 않습니다”


답변

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


답변

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

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

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

cc 매달려 있습니다.


답변

이것은 안전합니다.

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

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


답변

이 특정한 경우에 안전합니다. 그러나 모든 임시가 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)!


답변