const에 대한 rvalue 참조가 사용됩니까?


답변:


78

때때로 유용합니다. 초안 C ++ 0x 자체는 다음과 같이 몇 군데에서이를 사용합니다.

template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;

위의 두 오버로드는 다른 ref(T&)cref(const T&)함수가 rvalue에 바인딩되지 않도록합니다 (그렇지 않으면 가능함).

최신 정보

아쉽게도 공개적으로 사용할 수없는 공식 표준 N3290을 확인 했으며 20.8 Function 객체 [function.objects] / p2에 있습니다.

template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;

그런 다음 공개적으로 사용 가능한 최신 C ++ 11 이후 초안 인 N3485 를 확인했으며 20.8 함수 개체 [function.objects] / p2에서 여전히 다음과 같이 말합니다.

template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;

cppreference를 살펴보면 더 이상 그렇지 않은 것 같습니다. 이유는 무엇입니까? 다른 장소 const T&&가 사용됩니까?
Pubby

58
답변에 동일한 코드를 세 번 포함시킨 이유는 무엇입니까? 나는 너무 오랫동안 차이를 찾으려고 노력했다.
typ1232 2013

9
@ typ1232 : 참조 된 함수가 더 이상 나타나지 않는다는 의견에 대한 우려로 인해 답변 한 지 거의 2 년 후에 답변을 업데이트 한 것으로 보입니다. 나는 N3290과 그 당시 가장 최근의 초안 N3485에서 복사 / 붙여 넣기를하여 기능이 여전히 나타나는 것을 보여주었습니다. 당시 제 생각에는 복사 / 붙여 넣기를 사용하는 것이 제가이 서명의 사소한 변경을 간과하지 않았 음을 확인할 수있는 가장 좋은 방법이었습니다.
하워드 Hinnant

1
@kevinarpe : "기타 오버로드"(여기에 표시되지 않지만 표준에 있음)는 lvalue 참조를 사용하며 삭제되지 않습니다. 여기에 표시된 오버로드는 lvalue 참조를 사용하는 오버로드보다 rvalue와 더 잘 일치합니다. 따라서 rvalue 인수는 여기에 표시된 오버로드에 바인딩되고 이러한 오버로드가 삭제되므로 컴파일 시간 오류가 발생합니다.
Howard Hinnant

1
를 사용 const T&&하면 누군가 어리석게 형식의 명시 적 템플릿 인수를 사용하는 것을 방지 할 수 ref<const A&>(...)있습니다. 끔찍한 주장은 아니지만 const T&&오버 비용 T&&은 매우 적습니다.
Howard Hinnant

6

const rvalue 참조 (for가 =delete아님) 를 얻는 의미는 다음과 같은 의미입니다 .

  • lvalue에 대한 연산을 지원하지 않습니다!
  • 비록, 우리는 여전히 복사 우리가 할 수 없기 때문에, 이동 전달 된 자원을, 또는 실제 의미가 없기 때문에 그것을 "이동".

다음 사용 사례 수 있었다 이럴위한 좋은 사용 사례 를 const를 rvalue 참조 언어가이 방법을 (참조 걸릴하지 않기로 결정하지만, 원래의 SO 게시물을 ).


사례 : 원시 포인터의 스마트 포인터 생성자

일반적으로 사용하는 것이 좋습니다 것 make_unique하고 make_shared있지만, 모두 unique_ptrshared_ptr원시 포인터로 구성 될 수있다. 두 생성자 모두 값으로 포인터를 가져 와서 복사합니다. 둘 다 생성자에서 전달 된 원래 포인터의 연속 사용을 허용합니다 (예 : 방지하지 마십시오 ).

다음 코드는 double free로 컴파일되고 결과를 얻습니다 .

int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;

모두 unique_ptrshared_ptr그 관련 생성자가 원시 포인터를 얻을 것으로 예상한다면 위를 방지 할 수 CONST를 rvalue로 에 대한 예 unique_ptr:

unique_ptr(T* const&& p) : ptr{p} {}

이 경우 위 의 이중 자유 코드는 컴파일되지 않지만 다음은 다음과 같습니다.

std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership
std::unique_ptr<int> p2 { new int(7) };     // ok, rvalue

참고 ptr잠재적 인 버그가 완전히 사라되지 않도록 아직도 후 사용할 수는 이동되었다. 그러나 사용자가 std::move이러한 버그 를 호출해야하는 경우 일반적인 규칙에 해당합니다. 이동 된 리소스를 사용하지 마십시오.


다음과 같이 질문 할 수 있습니다. OK,하지만 왜 T* const&& p 입니까?

그 이유는 간단 합니다. unique_ptr const pointer에서 생성을 허용하기 때문입니다 . 그 기억 CONST의를 rvalue 참조가 단지보다 제네릭 를 rvalue 참조 가 모두 허용으로 constnon-const. 따라서 다음을 허용 할 수 있습니다.

int* const ptr = new int(9);
auto p = std::unique_ptr<int> { std::move(ptr) };

rvalue 참조 (컴파일 오류 : const rvaluervalue에 바인딩 할 수 없음) 만 기대한다면이 방법은 진행되지 않습니다 .


어쨌든, 이런 제안을하기에는 너무 늦었습니다. 그러나이 아이디어는 const 에 대한 rvalue 참조 의 합리적인 사용법을 제시합니다 .


비슷한 생각을 가진 사람들 사이에 있었지만 앞으로 나아갈 지원이 없었습니다.
Red.Wave

"자동 p = std :: unique_ptr {std :: move (ptr)};" "클래스 템플릿 인수 추론 실패"오류와 함께 컴파일되지 않습니다. "unique_ptr <int>"이어야한다고 생각합니다.
Zehui Lin

4

그것들은 허용되고 심지어 함수는를 기준으로 순위가 매겨 const지지만에서 참조하는 const 객체에서 이동할 수 없기 const Foo&&때문에 유용하지 않습니다.


"순위"발언이 정확히 무엇을 의미합니까? 과부하 해결과 관련이 있습니까?
fredoverflow

주어진 유형에 const rvalue-ref를 취하는 이동 ctor가있는 경우 왜 const rvalue-ref에서 이동할 수 없습니까?
Fred Nurk

6
@FredOverflow, 과부하 순위는 다음과 같습니다.const T&, T&, const T&&, T&&
Gene Bushuyev

2
@Fred : 소스를 수정하지 않고 어떻게 이동합니까?
fredoverflow

3
@Fred : 변경 가능한 데이터 멤버 또는이 가상 유형으로 이동하는 경우 데이터 멤버를 수정할 필요가 없습니다.
Fred Nurk

2

std :: ref 외에도 표준 라이브러리는 동일한 목적으로 std :: as_const의 const rvalue 참조를 사용합니다 .

template <class T>
void as_const(const T&&) = delete;

래핑 된 값을 가져올 때 std :: optional 에서 반환 값으로도 사용됩니다 .

constexpr const T&& operator*() const&&;
constexpr const T&& value() const &&;

뿐만 아니라 std :: get :

template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;

이는 아마도 래핑 된 값에 액세스 할 때 래퍼의 일관성뿐 아니라 값 범주를 유지하기위한 것입니다.

이것은 const rvalue ref-qualified 함수가 래핑 된 객체에서 호출 될 수 있는지 여부에 차이를 만듭니다. 즉, const rvalue ref 한정 함수의 용도를 알지 못합니다.


1

이것이 직접적으로 유용 할 것이라고 생각할 수는 없지만 간접적으로 사용될 수 있습니다.

template<class T>
void f(T const &x) {
  cout << "lvalue";
}
template<class T>
void f(T &&x) {
  cout << "rvalue";
}

template<class T>
void g(T &x) {
  f(T());
}

template<class T>
void h(T const &x) {
  g(x);
}

g 의 T 는 T const이므로 f 's x는 T const &&입니다.

이로 인해 f (객체를 이동하거나 사용하려고 할 때) 에 comile 오류가 발생할 가능성이 있지만 f 는 rvalue-ref를 가져 와서 rvalue를 수정하지 않고 lvalue에서 호출 할 수 없도록 할 수 있습니다 (너무 단순한 위의 예).

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