J'essaie de créer un J'ai essayé le code ci-dessous, mais Je reçois l'erreur de compilation p> Erreur: Utilisation de la fonction supprimée 'my_union :: ~ my_union ()' p>
BlockQuote> Qu'est-ce que je fais mal? P> vecteur code> qui peut contenir
string code> et
int code>.
#include <iostream>
#include <vector>
using namespace std;
union my_union
{
string str;
int a;
};
int main()
{
vector<my_union> v;
my_union u; // error: use of deleted function 'my_union::~my_union()'
u.str = "foo";
v.push_back(u);
return 0;
}
3 Réponses :
de ici p>
Si un syndicat contient un élément de données non statique avec une fonction de membre spécial non trivial (constructeur par défaut, copier / déplacement constructeur, affectation de copie / déplacement ou destructeur), cette fonction est supprimée par défaut dans l'Union et les besoins être défini explicitement par le programmeur. P> blockQuote>
Vous devez définir explicitement un destructeur de votre syndicat pour remplacer celui-ci automatiquement supprimé pour
chaîne code>. p>
Notez également que cela n'est valable que dans C ++ 11. Dans les versions antérieures, vous ne pouvez pas avoir de type avec des fonctions non triviales spéciales à l'intérieur d'une union du tout. P>
D'un point de vue pratique, cela ne peut toujours pas être une bonne idée. P>
"Peut ... ne pas être une bonne idée" - en effet. Lorsque vous avez des types avec des constructeurs ou destructeurs non triviaux, vous devez utiliser des appels de placement nouveaux et explicites pour stocker un objet différent de l'Union.
@CODESINCHAOS Un commentaire à cette question fait allusion à Boost :: Variante < / a>. Je ne l'ai pas utilisé moi-même mais de la description sur la page Web, il semble que vous sonnez, même en donnant exactement la situation dans la question à titre d'exemple.
avant C ++ 11, il n'a pas été autorisé à utiliser Les syndicats ne peuvent pas contenir un élément de données non statique avec un non-trivial
Fonction de membre spéciale (constructeur de copie, opérateur d'affectation de copie,
ou destructeur). p>
BlockQquote> Et depuis C ++ 11, vous pouvez utiliser std :: chaîne code> dans un syndicat comme cité ici :
std :: String Code> dans un syndicat Comme déjà répondu par @ rotem , vous devez définir un destructeur explicitement pour une chaîne ou appeler le destructeur explicitement p>
Lorsque vous créez un syndicat avec une classe qui ne constitue pas fondamentalement des données anciennes, en C ++ 11, il vous permet. Mais cela va et supprime implicitement la plupart des fonctions membres spéciales telles que le destructeur.
struct tagged_union { enum active {nothing, string, integer} which_active; template<active...As> using actives = std::integral_sequence<active, As...> using my_actives = actives<nothing, string, integer>; struct nothingness {}; union my_union { nothingness nothing; std::string str; int a; ~my_union() {}; } data; using my_tuple = std::tuple<nothingness, std::string, int>; template<active which> using get_type = std::tuple_element_t<(std::size_t)which, my_tuple>; template<class F> void operate_on(F&& f) { operate_on_internal(my_actives{}, std::forward<F>(f)); } template<class T, class F> decltype(auto) operate_on_by_type(F&& f) { return std::forward<F>(f)(reinterpret_cast<T*>(&data)); } // const versions go here private: // a small magic switch: template<active...As, class F> void operate_on_internal(actives<As...>, F&& f) { using ptr = void(*)(my_union*,std::decay_t<F>*); const ptr table[]={ [](my_union* self, std::decay_t<F>* pf){ std::forward<F>(*pf)(*(get_type<As>*)self); }..., nullptr }; table[which](&data, std::address_of(f)); } public: template<class...Args> tagged_union(Active w, Args&&...args) { operate_on([&](auto& t){ using T = std::decay_t<decltype(t)>(); ::new((void*)std::addressof(t)) T(std::forward<Args>(args)...); which = w; }); } tagged_union():tagged_union(nothing){} ~tagged_union() { operate_on([](auto& t){ using T = std::decay_t<decltype(t)>(); t->~T(); which=nothing; ::new((void*)std::addressof(t)) nothingness{}; // "leaks" but we don't care }); } };
Rouverts: C ++ 11 a grandement élargi ce qui est autorisé dans une union et
std :: string code>, entre autres, est maintenant autorisé.
@Petebecker Je reçois cela mais n'est pas couvert dans Ceci Réponse de la Q?
Comment envisagez-vous de «savoir» quel membre de l'Union à lire du vecteur plus tard?
@ M c'est une bonne question. Il n'y a qu'un petit nombre de chaînes possibles, alors j'allais vérifier l'élément de cordes pour l'égalité avec l'une de celles-ci, et si aucune correspondance, elle doit être un int. Je pense que cela ressemble à une idée terrible et évacuée par erreur.
@Nathanoliver - Cette question et cette réponse sont à partir de 2010, avant B> le changement qui a permis de cela. Un compilateur C ++ 11 doit B> Compiler le code qui met un
std :: string code> dans une union, la réponse correcte à cette question b> est que Le compilateur est faux. La réponse liée, qui parle de la raison pour laquelle cela n'a aucun sens, c'est également faux.
@cppbeginner qui ne peut pas fonctionner. Le
int code> chevauche la partie initiale de l'objet
STD :: String Code>. Donc s'il y avait en fait un
int code> là, la représentation
std :: string code> serait très i> corrompu en interne et que vous y accédez serait probablement résultats très étranges ou un crash. Formellement, il est un comportement indéfini pour accéder à un membre inactif d'une union.
@Angew tu as raison. Je ne le pensais pas. J'ai besoin de changer complètement mon approche.
@cppbeginner Vous voudrez peut-être consulter
Boost :: Variante code>
@Angew merci, c'est très utile. C'est ce que je vais faire.