Namespaces
Variants

std::launder

cppreference.net에서 가져옴
 
 
유틸리티 라이브러리
일반 유틸리티
관계 연산자 (C++20에서 폐기됨)
정수 비교 함수
(C++20)(C++20)(C++20)    
(C++20)
교체 및 타입 연산
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
공통 어휘 타입
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)



 
메모리 관리 라이브러리
할당자
메모리 자원
초기화되지 않은 저장소 (C++20까지*)
가비지 컬렉터 지원 (C++23까지)
 
 
헤더 <new>
template< class T >
constexpr T* launder( T* p ) noexcept;
(C++17부터)에서 정의됨

에 대한 비가상화 펜스. p가 나타내는 동일한 주소의 객체를 가리키는 포인터를 반환하며, 객체는 최종 파생 클래스가 원본 p 객체와 다른 새로운 기본 클래스 하위 객체일 수 있습니다. *p공식적으로, 다음이 주어졌을 때

포인터

  • 는 메모리 내 바이트의 주소 p를 나타냅니다.A객체
  • 는 주소 x에 위치하며, A
  • x는 의
  • 수명x 내에 있습니다.T의 타입은 모든 수준의 cv-한정자를 무시했을 때
  • 와 동일합니다.y결과를 통해 접근 가능한 모든 바이트는 p를 통해 접근 가능합니다 (바이트는 객체 z를 가리키는 포인터를 통해 접근 가능한 경우, 해당 바이트가 와 포인터 상호 변환 가능y한 객체 z의 저장소 내에 있거나,

가 요소인 바로 둘러싼 배열 내에 있는 경우).std::launder(p)그러면 T*는 객체 x를 가리키는

타입의 값을 반환합니다. 그렇지 않으면, 동작은 정의되지 않습니다. T가 함수 타입이거나 (cv-한정될 수 있는) void인 경우, 프로그램은 ill-formed입니다.

std::launder는 핵심 상수 표현식에서 사용될 수 있습니다. 단, 해당 인수의 (변환된) 값을 함수 호출 대신 사용할 수 있는 경우에만 가능합니다. 즉, std::launder는 상수 평가에서 제한을 완화하지 않습니다.

참고 사항

std::launder 는 인자에 아무런 영향을 미치지 않습니다. 해당 객체에 접근하기 위해서는 반환값을 사용해야 합니다. 따라서 반환값을 버리는 것은 항상 오류입니다.

std::launder 의 일반적인 사용 사례는 다음과 같습니다:

  • 동일한 타입의 기존 객체 저장소에 생성된 객체에 대한 포인터를 획득하는 경우, 이때 이전 객체에 대한 포인터는 재사용될 수 없음 (예: 두 객체 중 하나가 기본 클래스 하위 객체인 경우);
  • 객체에 저장소를 제공하는 객체의 포인터로부터 placement new 를 통해 생성된 객체에 대한 포인터를 획득하는 경우.

도달 가능성 제한은 std::launder 가 원본 포인터를 통해 접근할 수 없는 바이트에 접근하는 데 사용될 수 없도록 보장하여, 컴파일러의 탈출 분석을 방해하지 않게 합니다.

int x[10];
auto p = std::launder(reinterpret_cast<int(*)[10]>(&x[0])); // 정상
int x2[2][10];
auto p2 = std::launder(reinterpret_cast<int(*)[10]>(&x2[0][0]));
// 정의되지 않은 동작: x2[1]이 결과 포인터를 통해 x2[0]에 도달 가능하지만
// 소스에서는 도달할 수 없음
struct X { int a[10]; } x3, x4[2]; // 표준 레이아웃; 패딩이 없다고 가정
auto p3 = std::launder(reinterpret_cast<int(*)[10]>(&x3.a[0])); // 정상
auto p4 = std::launder(reinterpret_cast<int(*)[10]>(&x4[0].a[0]));
// 정의되지 않은 동작: x4[1]이 결과 포인터를 통해 x4[0].a에 도달 가능하지만
// (이는 x4[0]과 포인터 상호 변환 가능) 소스에서는 도달할 수 없음
struct Y { int a[10]; double y; } x5;
auto p5 = std::launder(reinterpret_cast<int(*)[10]>(&x5.a[0]));
// 정의되지 않은 동작: x5.y가 결과 포인터를 통해 x5.a에 도달 가능하지만
// 소스에서는 도달할 수 없음

예제

#include <cassert>
#include <cstddef>
#include <new>
struct Base
{
    virtual int transmogrify();
};
struct Derived : Base
{
    int transmogrify() override
    {
        new(this) Base;
        return 2;
    }
};
int Base::transmogrify()
{
    new(this) Derived;
    return 1;
}
static_assert(sizeof(Derived) == sizeof(Base));
int main()
{
    // 사례 1: 새로운 객체가 기본 하위 객체이지만 이전 객체가 완전한 객체이기 때문에
    // 투명하게 대체 가능하지 않음
    Base base;
    int n = base.transmogrify();
    // int m = base.transmogrify(); // 정의되지 않은 동작
    int m = std::launder(&base)->transmogrify(); // OK
    assert(m + n == 3);
    // 사례 2: 바이트 배열을 통해 제공된 저장 공간을 가진 새 객체에
    // 배열에 대한 포인터를 통해 접근
    struct Y { int z; };
    alignas(Y) std::byte s[sizeof(Y)];
    Y* q = new(&s) Y{2};
    const int f = reinterpret_cast<Y*>(&s)->z; // 클래스 멤버 접근은 정의되지 않은 동작:
                                               // reinterpret_cast<Y*>(&s)는
                                               // "s를 가리키는 포인터" 값을 가지며
                                               // Y 객체를 가리키지 않음
    const int g = q->z; // OK
    const int h = std::launder(reinterpret_cast<Y*>(&s))->z; // OK
    [](...){}(f, g, h); // [[maybe_unused]] 효과 유발
}

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
LWG 2859 C++17 도달 가능(reachable) 의 정의가 포인터-상호 변환 가능 객체로부터의
포인터 연산을 고려하지 않음
포함됨
LWG 3495 C++17 std::launder 가 상수 표현식에서 비활성 멤버에 대한 포인터를
역참조 가능하게 만들 수 있음
금지됨