Ich denke nicht, aber ich möchte bestätigen. Gibt es eine Verwendung für const Foo&&
, wo Foo
ist ein Klassentyp?
c++
c++11
const
rvalue-reference
Fredoverflow
quelle
quelle
const&&
sehr wichtig sind, obwohl er nicht sagt, warum: youtube.com/watch?v=JhgWFYfdIho#t=54m20sAntworten:
Sie sind gelegentlich nützlich. Der Entwurf C ++ 0x selbst verwendet sie an einigen Stellen, zum Beispiel:
template <class T> void ref(const T&&) = delete; template <class T> void cref(const T&&) = delete;
Die beiden oben genannten Überladungen stellen sicher, dass die anderen
ref(T&)
undcref(const T&)
Funktionen nicht an r-Werte gebunden sind (was sonst möglich wäre).Aktualisieren
Ich habe gerade den offiziellen Standard N3290 überprüft , der leider nicht öffentlich verfügbar ist und in 20.8 Funktionsobjekten [function.objects] / p2 enthalten ist:
template <class T> void ref(const T&&) = delete; template <class T> void cref(const T&&) = delete;
Dann überprüfte ich den neuesten öffentlich zugänglichen Entwurf nach C ++ 11, N3485 , und in 20.8 Funktionsobjekten [function.objects] / p2 heißt es immer noch:
template <class T> void ref(const T&&) = delete; template <class T> void cref(const T&&) = delete;
quelle
const T&&
verwendet?const T&&
verhindert, dass jemand törichterweise explizite Vorlagenargumente des Formulars verwendetref<const A&>(...)
. Das ist kein besonders starkes Argument, aber die Kosten fürconst T&&
OverT&&
sind ziemlich gering.Die Semantik des Erhaltens einer konstanten Wertreferenz (und nicht für
=delete
) besteht darin, zu sagen:Der folgende Anwendungsfall könnte meiner Meinung nach ein guter Anwendungsfall für den r-Wert-Verweis auf const gewesen sein , obwohl die Sprache beschlossen hat, diesen Ansatz nicht zu wählen (siehe Original-SO-Beitrag ).
Der Fall: Konstruktor für intelligente Zeiger aus Rohzeiger
Es wäre normalerweise ratsam,
make_unique
und zu verwendenmake_shared
, aber beidesunique_ptr
undshared_ptr
kann aus einem rohen Zeiger konstruiert werden. Beide Konstruktoren erhalten den Zeiger nach Wert und kopieren ihn. Beide erlauben (dh im Sinne von: nicht verhindern ) eine fortgesetzte Verwendung des ursprünglichen Zeigers, der im Konstruktor an sie übergeben wurde.Der folgende Code wird kompiliert und führt zu double free :
int* ptr = new int(9); std::unique_ptr<int> p { ptr }; // we forgot that ptr is already being managed delete ptr;
Sowohl
unique_ptr
undshared_ptr
könnte verhindern , dass die oben , wenn ihre entsprechenden Konstrukteure erwarten würde den Rohzeiger zu bekommen als const rvalue , zB fürunique_ptr
:unique_ptr(T* const&& p) : ptr{p} {}
In diesem Fall würde der oben genannte doppelte freie Code nicht kompiliert, aber der folgende würde:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
Beachten Sie, dass
ptr
dies auch nach dem Verschieben noch verwendet werden kann, sodass der potenzielle Fehler nicht vollständig behoben ist. Wenn der Benutzer jedoch einenstd::move
solchen Fehler aufrufen muss, fällt dies unter die allgemeine Regel: Verwenden Sie keine Ressource, die verschoben wurde.Man kann fragen: OK, aber warum
T*
const&& p
?Der Grund ist einfach, um die Erstellung eines
unique_ptr
konstanten Zeigers zu ermöglichen . Denken Sie daran , dass const rvalue Referenz ist allgemeinerer als nur rvalue Referenz , da sie sowohl akzeptiertconst
undnon-const
. Wir können also Folgendes zulassen:int* const ptr = new int(9); auto p = std::unique_ptr<int> { std::move(ptr) };
dies würde nicht gehen , wenn wir nur erwarten rvalue Referenz (Kompilierung - Fehler: kann nicht binden const rvalue zu rvalue ).
Jedenfalls ist dies zu spät, um so etwas vorzuschlagen. Diese Idee bietet jedoch eine vernünftige Verwendung eines r-Wert-Verweises auf const .
quelle
Sie sind zulässig und sogar nach Funktionen geordnet.
const
Da Sie sich jedoch nicht von dem angegebenen const-Objekt entfernen könnenconst Foo&&
, sind sie nicht nützlich.quelle
const T&, T&, const T&&, T&&
Neben std :: ref verwendet die Standardbibliothek für denselben Zweck auch die Konstantenwertreferenz in std :: as_const .
template <class T> void as_const(const T&&) = delete;
Es wird auch als Rückgabewert in std :: optional verwendet, wenn der umschlossene Wert abgerufen wird:
constexpr const T&& operator*() const&&; constexpr const T&& value() const &&;
Sowie in 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;
Dies dient vermutlich dazu, die Wertkategorie sowie die Konstanz des Wrappers beim Zugriff auf den umschlossenen Wert beizubehalten.
Dies macht einen Unterschied, ob const rvalue ref-qualifizierte Funktionen für das umschlossene Objekt aufgerufen werden können. Trotzdem kenne ich keine Verwendungszwecke für qualifizierte Funktionen mit konstantem Wert.
quelle
Ich kann mir keine Situation vorstellen, in der dies direkt nützlich wäre, aber es könnte indirekt verwendet werden:
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); }
Das T in g ist T const, also ist f 's x ein T const &&.
Es ist wahrscheinlich, dass dies zu einem Comile-Fehler in f führt (wenn versucht wird, das Objekt zu verschieben oder zu verwenden), aber f könnte einen rvalue-ref verwenden, so dass es nicht für lvalues aufgerufen werden kann, ohne den rvalue zu ändern (wie im zu einfachen Beispiel oben).
quelle