Der folgende Code:Ist das Verhalten von std :: get on rvalue-Referenztupeln gefährlich?
#include <tuple>
int main()
{
auto f = []() -> decltype (auto)
{
return std::get<0> (std::make_tuple (0));
};
return f();
}
(Lautlos) generiert Code mit undefiniertem Verhalten - die temporäre rvalue von make_tuple
zurückgegeben wird durch die std :: propagiert < bekommen> und durch die decltype (Auto) auf den Rückgabetyp. Es endet damit, dass ein Verweis auf ein temporäres Objekt zurückgegeben wird, das nicht mehr gültig ist. Sehen Sie es hier https://godbolt.org/g/X1UhSw.
Nun könnte man argumentieren, dass meine Verwendung von decltype(auto)
ist schuld. Aber in meinem generischen Code (wo der Typ des Tupels std::tuple<Foo &>
sein könnte) möchte ich nicht immer eine Kopie machen. Ich möchte wirklich den genauen Wert oder die Referenz aus dem Tupel extrahieren.
Mein Gefühl ist, dass diese Überlastung der std::get
gefährlich ist:
template< std::size_t I, class... Types >
constexpr std::tuple_element_t<I, tuple<Types...> >&&
get(tuple<Types...>&& t) noexcept;
Während Verweise auf Tupelelemente lvalue ausbreitende wahrscheinlich sinnvoll ist, ich glaube nicht, dass für rvalue Referenzen hält.
Ich bin mir sicher, dass das Standardkomitee dies sehr sorgfältig durchdacht hat, aber kann mir jemand erklären, warum dies als die beste Option angesehen wurde?
* "Ich denke nicht, dass das für Rvalue Referenzen gilt" * - Es tut, wenn Sie 'forward_as_tuple'. Sie möchten, dass die Wertkategorie beibehalten wird. Oder wenn Sie einen Wert aus einem Rückgabewert einer Funktion extrahieren möchten. – StoryTeller
Danke, aber ich bin nicht wirklich sicher, dass es die Wertkategorie bewahrt. Zum Beispiel, wenn ich eine Funktion habe, die ein 'std :: tuple' zurückgibt und ich 'std :: get <0>' darauf nenne, würde ich erwarten, ein einfaches 'int' zu erhalten, kein' int && '. Können Sie mir ein konkretes Beispiel geben, wo Sie etwas anderes wollen? –
Wird diese Überladung von 'get' nicht für effektive strukturierte Bindungen benötigt? –