J'ai une classe qui doit contenir une référence à certaines données, sans posséder ces données (c'est-à-dire que les données réelles sont garanties de ne pas sortir du cadre). En particulier, la classe ne peut pas faire une copie - les données sont facilement de plusieurs gigaoctets.Titulaire non détenteur de sémantique d'affectation
Maintenant, la mise en œuvre habituelle (je suppose) est d'avoir une référence aux données:
struct holder_ref {
type const& value;
holder_ref(type const& value) : value(value) { }
};
(S'il vous plaît noter que la RNS const
n'a absolument aucune incidence sur le problème). Maintenant, j'ai absolument besoin que cette classe soit assignable (c'est-à-dire qu'elle ait un operator =
fonctionnel). Je pensais que c'était un problème assez commun, mais je ne me souviens pas comment (si jamais) je l'ai résolu avant.
Le problème est que une référence ne peut pas être affectée et il n'y a tout simplement pas moyen de contourner cela. La seule solution que je suis venu avec des utilisations nouvelles de placement en place de l'opérateur d'affectation:
// x = other_x; gets replaced with:
x.~T();
new (&x) T(other_x);
Maintenant, cela fonctionne et est conforme à la norme. Mais c'est sûr que c'est moche. Non - inacceptable.
Alors je cherche des alternatives. Une idée est d'utiliser des pointeurs, mais je ne suis pas certain que mon constructeur est effectivement garanti au travail (et le passage d'un pointeur est impossible en raison de l'interface que je dois adhérer à):
struct holder_ptr {
type const* value;
// Is this legal?
holder_ptr(type const& value = 0) : value(&value) { }
};
Mais je préfère utiliser une référence, si possible. Seulement - comment implémenter l'opérateur d'affectation?
struct holder_ref {
type const& value;
holder_ref(type const& value = 0) : value(value) { }
holder_ref& operator =(holder_ref const& other) {
// Now what?!
return *this;
}
};
En cas de test, considérez le code suivant:
int main() {
int const TEST1 = 23;
int const TEST2 = 13;
int const TEST3 = 42;
std::vector<holder_ptr> hptr(1);
std::vector<holder_ref> href(2);
// Variant 1. Pointer.
hptr[0] = holder_ptr(TEST1);
// Variant 2. Placement new.
href[0].~holder_ref();
new (&href[0]) holder_ref(TEST2);
// Variant 3. ???
href[1] = holder_ref(TEST3);
assert(*hptr[0].value == TEST1); // Works (?)
assert(href[0].value == TEST2); // Works
assert(href[1].value == TEST3); // BOOM!
}
(Aussi, pour que cela soit clair - le type dont nous parlons est non-POD et je besoin d'un conforme à la norme solution.)
Quel est le problème avec la solution de pointeur? Cela semble correspondre parfaitement à votre cas d'utilisation. C'est un membre assignable et il n'exprime pas ou n'implique pas la propriété. –
Bien que vous ne puissiez pas stocker légitimement un pointeur sur un temporaire, votre valeur par défaut pour la valeur: 'holder_ptr (type const & value = 0)' est imprudente. (Mais cela aurait été aussi valable pour les références.) –
@Charles: oui, c'est un autre problème que la solution de référence a. –