2011-01-10 1 views
1

J'ai une classe contenant plusieurs membres d'un type de classe simple. Plus important encore, leur nombre augmente au fur et à mesure du développement.comment réinitialiser un grand nombre de membres de la classe à la fois, pas dans un destructeur?

Je dois être en mesure de les réinitialiser tous en même temps, et je voudrais le faire sans copier-coller. Le code ressemble actuellement:

typedef auto_ptr<odbc::PreparedStatement> Stmt; 

class DbProxy { 
private: 
    void reset(); 

    Stmt a; 
    Stmt b; 
    Stmt c; 
    // ... about 10 more 
}; 

void DbProxy::reset() 
{ 
    a.reset(); 
    b.reset(); 
    c.reset(); 
    // etc. 
} 

Il est évident que je n'aime pas avoir à ajouter chaque nouveau membre à la fonction reset() (juste eu une faute seg pour oublier un.).

Ce que j'ai l'intention de faire est de les rassembler tous dans une structure et d'allouer cette structure sous auto_ptr. Ainsi, le code ressemblerait à ceci:

typedef auto_ptr<odbc::PreparedStatement> Stmt; 

class DbProxy { 
public: 
    DbProxy(): stmts(new OdbcResources) {} 
private: 
    void reset() { stmts.reset(); } 

    struct OdbcResources { 
    Stmt a; 
    Stmt b; 
    Stmt c; 
    // ... about 10 more 
    }; 
    auto_ptr<OdbcResources> stmts; 
}; 

objets de DbProxy ne sont pas destinés à être copiés ou copie construite, bien que je ne l'ai pas pris la peine d'en assurer en faisant la cession et la copie-cteur privé.

Voyez-vous un problème avec cette approche? Avez-vous d'autres suggestions?

EDIT

basée sur la suggestion @DeadMG, qu'en ceci:

class DbProxy { 
public: 
    DbProxy(); 
private: 
    enum Statements { SELECT1, SELECT2, INSERT, LAST }; // never mind the names 

    void reset() { for (int i=0; i < LAST; i++) statement[i].reset(); } 

    Stmt statements[LAST]; 
}; 
+0

Pouvez-vous mettre vos objets 'Stmt' dans un tableau? De cette façon, vous pouvez gérer n'importe quel nombre arbitraire d'entre eux. –

+0

pourquoi pas un conteneur d'objets 'shared_ptr <>'? – Nim

+0

@Robert, impossible ce sont 'auto_ptr' - qui ne peuvent pas être stockés dans un conteneur – Nim

Répondre

2

Il n'y a pas besoin pour le auto_ptr supplémentaire (chaque Stmt étant un auto_ptr de toute façon), si vous les recueillir dans une seule classe, vous pouvez les remettre avec une simple affectation. Contrairement à une solution de tableau, vous conservez toujours leurs noms significatifs.

Notez que vous ne pouvez pas utiliser un temporaire sans nom (par exemple stmts = OdbcResources();) comme l'opérateur d'affectation de copie généré prendra une référence non const que les membres (auto_ptr) ne peut être affectée de non constauto_ptr s.

class DbProxy { 
public: 
    DbProxy() : stmts() {} 
private: 
    void reset() { OdbcResources tmp; stmts = tmp; } 

    struct OdbcResources { 
    Stmt a; 
    Stmt b; 
    Stmt c; 
    // ... about 10 more 
    }; 
    OdbcResources stmts; 
}; 
+0

c'est probablement la solution la plus simple. Pourriez-vous élaborer le deuxième point, à propos de l'intérimaire sans nom? – davka

+2

@davka: Le compilateur ne peut pas générer d'opérateur d'affectation de copie avec la signature 'OdbcResources & operator = (const OdbcResources &)' car l'affectation memberwise échouera pour 'auto_ptr' qui prend une référence non -const' dans son opérateur d'affectation de copie . Le compilateur doit générer un opérateur d'affectation de copie avec la signature 'OdbcResources & operator = (OdbcResources &)'. Parce que vous ne pouvez pas lier un temporaire à une référence non-'const'' stmts = OdbcResources() 'ne compilera plus maintenant. –

+0

merci, il est clair maintenant – davka

3

utiliser un tableau statique de taille.

Stmt statements[10]; 

for(int i = 0; i < sizeof(statements)/sizeof(Stmt); i++) 
    statements[i].reset(); 
+0

merci, il m'est apparu, mais il y a un problème - actuellement, ils ont chacun un nom significatif et sont utilisés dans diverses méthodes fournies par la classe DbProxy. Avec un tableau, je devrai me référer à eux par 'statements [3]' plutôt que 'insertStmt', ce qui peut causer des erreurs et de la confusion. – davka

+0

Je pourrais peut-être utiliser enum pour cela? S'il vous plaît voir la modification dans mon OP – davka

+0

@davka: Vous pourriez simplement faire de petites fonctions d'aide. 'Stmt & GetInsertStmt() {instructions de retour [3]; } '. Un enum fera aussi le travail. 'enum {InsertStmt = 0, UpdateStmt = 1};' où vous pouvez passer l'énumération directement en tant qu'index de tableau. – Puppy

1

Ce pleure pour un récipient - en supposant odbc::PreparedStatement est copiable, ont tout simplement un vecteur de ces derniers dans DbProxy

class DbProxy { 
private: 
    void reset() { resources.clear(); } // all vanish! 

    vector<odbc::PreparedStatement> resources; 
}; 

Else, shared_ptr

typedef shared_ptr<odbc::PreparedStatement> Stmt; 
class DbProxy { 
private: 
    void reset() { resources.clear(); } // all vanish! 

    vector<Stmt> resources; 
}; 
+0

merci. La librairie que j'utilise (odbC++) me donne seulement un pointeur sur 'odbc :: PreparedStatement' donc je ne peux pas utiliser la première option. La seconde est intéressante, cependant. – davka

+0

Si votre bibliothèque ne vous transfère pas la propriété de 'odbc :: PreparedStatement', la seconde ne fonctionnera pas non plus parce que' shared_ptr' et la bibliothèque penseront qu'ils sont propriétaires. –

+0

@Mark B: pas sûr - leurs échantillons utilisent 'auto_ptr' qui supprime le pointeur quand il sort de la portée, donc je suppose qu'ils transfèrent la propriété (en quelque sorte, parce que quand je réinitialise la connexion à l'instruction, je obtenir seg. faute en essayant d'utiliser/supprimer la déclaration.Il ressemble donc à une propriété partagée ...) – davka

0

Vous pourriez être en mesure de il suffit de copier dans une copie par défaut:

void reset() { *this = DbProxy(); } 
+0

c'est intéressant, mais l'air un peu brutal, n'est ce pas? Quoi qu'il en soit, il suppose que je n'ai rien dans la classe ** mais ** ces déclarations. – davka

+0

Oui, mais qu'en est-il de 'stmts.reset (new OdbcResources);' juste réinitialiser les instructions préparées aux éléments construits par défaut? –

+0

@Mark B: oui, c'est mieux – davka

1

Je ne vois rien de mal à ce type d'approche. Cela ressemble à l'idiome "implémentation privée". Vous pouvez être intéressé par le details.

MY2C

Questions connexes