P0137 은 함수 템플릿을 소개하고 std::launder
공용체, 수명 및 포인터에 관한 섹션에서 표준을 많이, 많이 변경합니다.
이 백서가 해결하는 문제는 무엇입니까? 내가 알아야 할 언어에 어떤 변화가 있습니까? 그리고 우리는 무엇을하고 launder
있습니까?
P0137 은 함수 템플릿을 소개하고 std::launder
공용체, 수명 및 포인터에 관한 섹션에서 표준을 많이, 많이 변경합니다.
이 백서가 해결하는 문제는 무엇입니까? 내가 알아야 할 언어에 어떤 변화가 있습니까? 그리고 우리는 무엇을하고 launder
있습니까?
답변:
std::launder
당신이 그것이 무엇인지 알고있는 경우에만 적절하게 이름이 지정됩니다. 메모리 세탁을 수행 합니다 .
논문의 예를 고려하십시오.
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
이 문은 집계 초기화를 수행하여 U
with 의 첫 번째 멤버를 초기화합니다 {1}
.
때문에 n
A는 const
변수, 컴파일러는 그 가정에 무료로 u.x.n
하여야한다 항상 일을합니다.
이렇게하면 어떻게됩니까?
X *p = new (&u.x) X {2};
X
사소한 것이기 때문에 새로운 객체를 만들기 전에 이전 객체를 파괴 할 필요가 없으므로 완벽하게 법적인 코드입니다. 새로운 객체는n
멤버는 2입니다.
말해봐 ... 무슨 일이 u.x.n
돌아 올까?
명백한 대답은 2입니다. 그러나 컴파일러는 진정한 const
변수 (단지 const&
, 그러나 선언 된 객체 변수 const
) 가 절대 변하지 않는다고 가정 할 수 있기 때문에 잘못 되었습니다 . 그러나 우리는 방금 변경했습니다.
[basic.life] / 8 은 변수 / 포인터 / 이전 객체에 대한 참조를 통해 새로 생성 된 객체에 액세스 할 수있는 상황을 설명합니다. 그리고 const
회원을 갖는 것은 실격 요소 중 하나입니다.
그럼 ... 어떻게 이야기 할 수 u.x.n
있을까요?
우리는 기억을 세탁해야합니다.
assert(*std::launder(&u.x.n) == 2); //Will be true.
자금 세탁은 사람들이 돈을 얻은 곳을 추적하지 못하도록하는 데 사용됩니다. 메모리 세탁은 컴파일러 가 객체를 가져온 위치를 추적 하지 못하도록하여 더 이상 적용되지 않는 최적화를 피하도록합니다.
실격 요인 중 하나는 개체 유형을 변경하는 경우입니다. std::launder
여기에도 도움이 될 수 있습니다.
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life] / 8 은 이전 오브젝트의 스토리지에 새 오브젝트를 할당하면 이전 오브젝트에 대한 포인터를 통해 새 오브젝트에 액세스 할 수 없음을 알려줍니다. launder
우리는 그것을 회피 할 수 있습니다.
n
는 const
변수 이기 때문에 컴파일러는 u.x.n
항상 1 이라고 가정 할 수 있습니다." 표준 어디에서 그렇게 말합니까? 나는 당신이 지적한 바로 그 문제가 처음에는 그것이 거짓이라는 것을 암시하는 것처럼 보이기 때문에 묻습니다. as-if 규칙에서만 적용되어야하며 여기서 실패합니다. 내가 무엇을 놓치고 있습니까?
ptr
표시된 T 유형의 객체가없는 경우 launder
사전 조건 을 위반 하므로 결과에 대해 이야기 할 필요가 없습니다.
memcpy
지원되는 (즉, lax alignment) 플랫폼에서 올바른 해석을 올바른 솔루션으로 최적화합니다 .
std::launder
있습니까?std::launder
"const 또는 reference 멤버가 있더라도 동일한 유형의 기존 오브젝트가 차지하는 스토리지에서 작성된 오브젝트에 대한 포인터를 얻는 데 사용됩니다."