Referenz mit Standardwert?
-
Die Autoren setzen wohl voraus, dass [
first,last[ eine gültige Iterator-Range ist, also keinend()mittendrin. Wahrscheinlich hierauf bezogen:§24.1/7 Iterator requirements schrieb:
Most of the library’s algorithmic templates that operate on data structures have interfaces that use ranges. A range is a pair of iterators that designate the beginning and end of the computation. A range [i, i) is an empty range; in general, a range [i, j) refers to the elements in the data structure starting with the one pointed to by i and up to but not including the one pointed to by j. Range [i, j) is valid if and only if j is reachable from i. The result of the application of functions in the library to invalid ranges is undefined.
-
Ja, aber darf ich mit * ein Objekt ziehen, das nicht konstruiert wurde?
string* s=new string; delete s; *s;//erlaubt? &*s;//erlaubt?Ich denke nicht (*an meine Sig denk*).
Oder mitr Iteratoren
vector<string> v; v.reserve(1); *v.begin();//erlaubt? &*v.begin();//erlaubt?
-
Ah, ich dachte jetzt nur gerade an
end(). Aber voruninitialized_copy()ist ja der Speicher ein Trümmerfeld.Nein, du hast Recht. Ich würde auch sagen, auf Raw-Speicher darf man Iteratoren nicht dereferenzieren, auch nicht vorübergehend.
Was gäbe es denn für Alternativen?
operator->gäbe einenT*zurück, sieht schon mal gut aus. Meinst du, sowas wäre ok?new (static_cast<void*>(result.operator->())) T(...)
-
Nexus schrieb:
Ah, ich dachte jetzt nur gerade an
end(). Aber voruninitialized_copy()ist ja der Speicher ein Trümmerfeld.Ich dachte an end() eines Arrays. Da ist ja versprochen, daß die Zeigerarithmetik noch funktioniert, ich bin sogar bisher immer davon augegangen, daß der Speicher von *end() da ist, aber halt ein Trümmerfeld. Deswegen habe ich den Fall vorhin in der end-Schublade gefunden.
-
Um nochmal auf den ursprünglichen Fall zurückzukommen, es gibt mehrere Wege, so ein Interface zu realisieren. Am einfachsten ist wohl Überladung, etwa
namespace impl { void call_backend(std::string const &strModule, HMODULE *hModule) { HMODULE hTemp = NULL; // mach was if (hModule != NULL) { *hModule = hTemp; } } } void Call(std::string strModule) { impl::call_backend(stdModule, NULL); } void Call(std::string strModule, HMODULE &hModule) { impl::call_backend(strModule, &hModule); }Eine andere Möglichkeit, vor allem dann sinnvoll, wenn das ganze oft gebraucht wird, wäre eine Klassenvorlage, die die Referenz verwaltet, beispielsweise (ungetestet)
template<typename T> class optional_ref { public: optional_ref() : ref_(0) { } optional_ref(T &ref) : ref_(&ref) { } // Hier kann man natürlich auch allerlei mit Operatorüberladung // machen, um die Benutzung natürlicher zu gestalten. void set(T const &val) { *ref_ = val; } T const &get() const { return *ref; } bool valid() const { return ref != 0; } private: T *ref_; }; void Call(std::string strModule, optional_ref<HMODULE> hModule = optional_ref<HMODULE>()) { HMODULE hTemp = NULL; // mach was if (hModule.valid()) { hModule.set(hTemp); } }
-
Dein optional_ref<T> würde ich mit boost::optional<T&> ersetzen. Finde aber beides nicht so toll.
Überladung FTW!
Kann man - wie ich ja bereits gezeigt habe - auch einfacher machen.
-
Nexus schrieb:
Ah, ich dachte jetzt nur gerade an
end(). Aber voruninitialized_copy()ist ja der Speicher ein Trümmerfeld.Nein, du hast Recht. Ich würde auch sagen, auf Raw-Speicher darf man Iteratoren nicht dereferenzieren, auch nicht vorübergehend.
Was gäbe es denn für Alternativen?
operator->gäbe einenT*zurück, sieht schon mal gut aus. Meinst du, sowas wäre ok?new (static_cast<void*>(result.operator->())) T(...)LOL!
Wie einfach. Ich habs damals nicht hingekriegt. Bin einfach nicht auf die Idee gekommen, den operator-> aufzurufen. Mir hätte das gereicht.
Ganz ok? Weiß nicht, wie ich 24.1.1 zu verstehen habe, er muß nur it->m haben, falls (*it).m geht. Und das geht, sobald der Iterator ein Template ist und Klasseninstanzen verwalten könnte. Aber naja, besser als &* ist es sicherlich, denn my_vector<int>::iterator::operator*() könnte ja einen Proxy zurückgeben, der...
Oh, vector<bool>
Der operator-> kann auch einen Proxy zurückgeben.
Bin wieder verwirrt.
-
volkard schrieb:
LOL!
Wie einfach. Ich habs damals nicht hingekriegt. Bin einfach nicht auf die Idee gekommen, den operator-> aufzurufen. Mir hätte das gereicht.Hab zuerst auch gedacht, man müsse wohl eine Funktion haben, die von Iteratoren den Zeiger extrahieren kann. Dann hatte ich plötzlich diesen Geistesblitz. Liegt wohl an der Uhrzeit...

volkard schrieb:
denn my_vector<int>::iterator::operator*() könnte ja einen Proxy zurückgeben, der...
Du meinst wegen des
reference-Typedefs? Kennst du ausservector<bool>eine Implementierung, die nichtT&zurückgibt (nicht, dass man es nicht dürfte, interessiert mich nur)?volkard schrieb:
Oh, vector<bool>
Der operator-> kann auch einen Proxy zurückgeben.
Bin wieder verwirrt.Ja,
vector<bool>bekämpft leider Generizität, wo er nur kann. Eigentlich sollte man den rauswerfen. Ich frage mich, wie viele Programmierer schon von dessen Speicherersparnis profitiert haben? Mitstd::bitsetundboost::dynamic_bitsetgibt es ohnehin fähigere Klassen.
-
Nexus schrieb:
volkard schrieb:
denn my_vector<int>::iterator::operator*() könnte ja einen Proxy zurückgeben, der...
Du meinst wegen des
reference-Typedefs? Kennst du ausservector<bool>eine Implementierung, die nichtT&zurückgibt (nicht, dass man es nicht dürfte, interessiert mich nur)?Mit so Sachen habe ich damals angefangen. Auf einem 386-er mit DOS und "Dinge" mußten beim Dereferenzieren automatisch aus den 4M extended memory oder gar von Platte in den Bereich unter 640k hüpfen. Deswegen denke ich recht früh an Proxies. Aber ich kenne gerade keine. Das macht ja heute alles die Hardware.
-
Handelt zwar etwas vor meiner C++-Zeit, aber ist durchaus interessant

An sowas hätte ich jetzt nicht gedacht...
-
Es dürfen ja ausser bei T=bool auch gar keine Proxies zurückgegeben werden.
-
volkard schrieb:
Nexus schrieb:
Compiler viel weniger optimieren und klug sein. Steht das wirklich drin?
20.4.4.1
(Kann aus meiner pdf nicht copy&pasten, ich nehme den entsprechenden von http://www.cplusplus.com/reference/std/memory/uninitialized_copy/ )The behavior of this function template is equivalent to:
template<class InputIterator, class OutputIterator> OutputIterator copy ( InputIterator first, InputIterator last, OutputIterator result ) { for (; first!=last; ++result, ++first) new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first); return result; }schöner bug. result muss natürlich mindestens ein ForwardIterator sein. Das impliziert reservierten Speicher (3.8), und stellt somit kein Problem für den Adressoperator dar.
Übrigens wissen wir schon aus C-Zeiten dass das Derefenzieren von Zeigern auf unitialisertem Speicher zulässig ist. Wie oft macht(e) man dort
struct foo { int x }; struct foo* p = malloc(sizeof(*p)); p->x = 1;
-
camper schrieb:
volkard schrieb:
Nexus schrieb:
Compiler viel weniger optimieren und klug sein. Steht das wirklich drin?
20.4.4.1
(Kann aus meiner pdf nicht copy&pasten, ich nehme den entsprechenden von http://www.cplusplus.com/reference/std/memory/uninitialized_copy/ )The behavior of this function template is equivalent to:
template<class InputIterator, class OutputIterator> OutputIterator copy ( InputIterator first, InputIterator last, OutputIterator result ) { for (; first!=last; ++result, ++first) new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first); return result; }schöner bug. result muss natürlich mindestens ein ForwardIterator sein. Das impliziert reservierten Speicher (3.8), und stellt somit kein Problem für den Adressoperator dar.
Hoffentlich reden wir von uninitialized_copy.
camper schrieb:
Übrigens wissen wir schon aus C-Zeiten dass das Derefenzieren von Zeigern auf unitialisertem Speicher zulässig ist. Wie oft macht(e) man dort
struct foo { int x }; struct foo* p = malloc(sizeof(*p)); p->x = 1;Im sizeof hatten wir keine Schmerzen.