std::vector: Konstruktor-Verhalten ändern
-
Warum jetzt plötzlich
shared_ptr? Das brauchst du doch nicht.Ich hätte eher an sowas gedacht:
handle_wrapper create_socket(); int main() { std::vector<handle_wrapper> vector; std::generate_n(std::back_inserter(vector), 5, &create_socket); }
-
Das macht leider eine Copy-Operation?! Jedenfalls sind im
vectordann die selben Handle-Werte.
-
Ad aCTa schrieb:
Das macht leider eine Copy-Operation?! Jedenfalls sind im
vectordann die selben Handle-Werte.Sofern du
create_socket()so implementierst, dass es nicht jedes Mal dasselbe Objekt zurückgibt, sind die neuen Elemente imstd::vectorauch unterschiedlich.Die STL-Algorithmen
std::generate()undstd::generate_n()rufen die Generatorfunktion für jedes Element auf – etwa im Gegensatz zustd::fill()undstd::fill_n().
-
> Sofern du create_socket() so implementierst, dass es nicht jedes Mal dasselbe Objekt zurückgibt, sind die neuen Elemente im std::vector auch unterschiedlich.
Das will ich auch meinen.
Die Implementierung der Funktion ist trivial:inline socket_handle create_socket() { return socket_handle(); }Dabei kann es ja unmöglich immer das selbe Objekt sein?!
-
Ad aCTa schrieb:
Dabei kann es ja unmöglich immer das selbe Objekt sein?!
Wenn du meinen Rat befolgt hast und der Defaultkonstruktor immer die gleiche Initialisierung durchführt, doch. Ansonsten passe deine Wertsemantik an, dass
socket_handle a; socket_handle b; assert(a == b);gilt (falls
operator==nicht existiert, denk dir eine sinnvolle Implementierung für dieses Gedankenexperiment aus).Objekt-spezifische Initialisierungen sollten wie schon gesagt nicht im Defaultkonstruktor geschehen. Entsprechend müsste
create_socket()auch mehr tun als nur Default- und Kopierkonstruktor aufzurufen.
-
Das ändert nichts. Selbst wenn ich die Semantik herstelle und
inline socket_handle create_socket() { socket_handle sh; sh.init_(); return sh; }schreibe, bleiben die Handles gleich?!
-
Kannst du diesen Code kompilieren und sagen, wie bei dir die Ausgabe aussieht?
#include <vector> #include <algorithm> #include <iterator> #include <iostream> int create_int() { static int i; return ++i; } void output(int i) { std::cout << i << " "; } int main() { std::vector<int> vector; std::generate_n(std::back_inserter(vector), 5, &create_int); std::for_each(vector.begin(), vector.end(), &output); }
-
Logischerweise 1 2 3 4 5.
-
Gut, also ist deine Implementierung von
generate_n()in Ordnung.Kannst du etwas mehr Code posten? Wie sehen Kopier- und Standardkonstruktor von
socket_handleaus? Kannst du die Funktioncreate_socket()und die Stelle ihrer Verwendung (beim Füllen des Containers) zeigen?
-
vector<socket_handle> sockets; generate_n(std::back_inserter(sockets), 3, create_socket); for_each(sockets.begin(), sockets.end(), [](const socket_handle& sh) { cout << sh.get() << endl; }); // Kopierkonstruktor und Zuweisungsoperator sind compilergeneriert inline socket_handle create_socket() { socket_handle sh; sh.init_(); return sh; } struct socket_handle { socket_handle() throw(std::runtime_error) : used_(false), handle_(0) { } bool used() const { return used_; } ~socket_handle() { /* Handle freigeben */ } const SOCKET& get() const throw() { return handle_; } friend socket_handle create_socket(); private: void init_() { // Handle anfordern } bool used_; SOCKET handle_; };Nicht mehr und nicht weniger.
// EDIT:
Au weia, jetzt fällt mir was ein. Da der Destruktor ja beim Beenden von
create_socketaufgerufen wird, wird die Ressource freigegeben, sodass es beim nächsten Aufruf wieder die selbe Ressource ist, die ich dann bekomme. Scheinbar muss ich doch den Heap benutzen.
-
So, ich glaube, in diesem Fall ist das gute alte Array immernoch die einfachste Lösung.

-
Ad aCTa schrieb:
Au weia, jetzt fällt mir was ein. Da der Destruktor ja beim Beenden von
create_socketaufgerufen wird, wird die Ressource freigegeben, sodass es beim nächsten Aufruf wieder die selbe Ressource ist, die ich dann bekomme. Scheinbar muss ich doch den Heap benutzen.
Ja, dann scheint das sinnvoll zu sein. Wäre ja auch blöd, wenn bei einer Vector-Reallokation plötzlich alle Ressourcen freigegeben würden. Daher immer schön schauen, dass man so oft wie möglich eine sinnvolle Wertsemantik hat, besonders bei Containern.

Ad aCTa schrieb:
So, ich glaube, in diesem Fall ist das gute alte Array immernoch die einfachste Lösung.

Wenigstens
std::tr1::arrayläge also schon drin.