2010-08-30 8 views
1

J'ai lu sur les objets POD en C++. Je veux avoir une structure POD à écrire dans un fichier. Donc, il devrait avoir seulement des données publiques sans les ctors/dtors etc. Mais pour autant que je sache, il peut avoir une fonction statique. Alors, est-ce que je peux employer "l'idiome nommé par constructeur" ici? J'ai besoin d'initialisation dynamique, mais je ne veux pas reproduire les arguments de vérification à chaque initialisation struct Voici un exemple simple (il est juste simple, exemple, pas un code de travail):C++ initialisation POD

struct A 
{ 
    int day; 
    int mouth; 
    int year; 

    static A MakeA(const int day, const int month, const int year) 
    { 
     // some simple arguments chech 
     if (!(day >= 1 && day <= 31) || !(month >=1 && month <=12) || !(year <= 2010)) 
     throw std::exception(); 

     A result; 
     result.day = day; 
     result.month = month; 
     result.year = year; 
     return result; 
    } 
}; 

J'ai donc quelques-uns une sorte de constructeur et une structure POD que je peux simplement écrire dans un fichier? C'est correct?

+0

Mieux vaut utiliser std :: runtime_error Ensuite, vous pouvez ajouter un message d'erreur. –

+4

Pourquoi voulez-vous une structure POD pour écrire dans un fichier? Ceci est intrinsèquement non portable. Il est beaucoup plus simple d'écrire les opérateurs de flux appropriés. –

+0

Une structure ou une classe contenant des fonctions membres de tout type autre que virtuel peut toujours être écrite dans un fichier; Je ne comprends pas ce que vous pensez que le problème est avec ça? Tant qu'il s'agit d'un type de données composite "plat" (c'est-à-dire, pas de pointeurs vers des données détenues hors de la classe), et pas de fonctions virtuelles. Les fonctions membres ordinaires ne contribuent pas à la taille ou à la constitution de l'objet. – Clifford

Répondre

4

Cela devrait aller.

Vous pouvez même avoir un fonctions membres non statiques (tant qu'ils ne sont pas virtuelles)

Vous ne pouvez pas avoir quelque chose qui est appelé automatiquement (comme cteur/dtor). Thingsthat que vous appelez explicitement sont bien.

+0

Je suggérerais que vous pouvez avoir un constructeur ou un destructeur. Je ne suis pas sûr du problème. – Clifford

+3

@Clifford nous évaluons cela dans un sens formel strict. En pratique, avoir un constructeur ne nuira pas. Vous pourrez toujours utiliser 'memcpy'. Mais dans un sens formel, lorsque vous faites cela, vous n'êtes pas garanti que lorsque vous le rechargez, vous obtenez la même valeur à nouveau. –

+2

@Clifford: cela dépend si vous écrivez à la norme ou à l'implémentation. En vertu de la norme actuelle, une classe avec un constructeur est non-POD, donc si vous voulez que le POD garantisse qu'une copie octet-by-byte est un objet valide, vous ne pouvez pas avoir de constructeur. Avec la plupart des implémentations actuelles, vous avez tout à fait raison: la simple existence d'un constructeur ne posera aucun problème avec la validité d'une copie octet par octet d'un objet. Évidemment, il y a des choses qu'un constructeur pourrait faire (comme stocker «ceci») qui causeraient des problèmes, mais ils sont facilement évités. –

1

Si vous écrivez les opérateurs de flux, cela rend la vie beaucoup plus simple.
Ce n'est pas comme si écrire en binaire était beaucoup plus rapide (comme vous avez besoin d'écrire le code à convertir pour différents formats d'endian) et l'espace de nos jours est pratiquement hors de propos.

struct A 
{ 
    int day; 
    int mouth; 
    int year; 

    A(const int day, const int month, const int year) 
    { 
     // some simple arguments chech 
     if (!(day >= 1 && day <= 31) || !(month >=1 && month <=12) || !(year <= 2010)) 
     throw std::exception(); 

     this->day = day; 
     this->month = month; 
     this->year = year; 
    } 
}; 
std::ostream& operator<<(std::ostream& str, A const& data) 
{ 
    return str << data.day << " " << data.month << " " << data.year << " "; 
} 
std::istream& operator>>(std::istream& str,A& data) 
{ 
    return str >> data.day >> data.month >> data.year; 
} 

Avec ceci défini la plethera entière des algorithmes standard devient disponible et facile à utiliser.

int main() 
{ 
    std::vector<A> allDates; 
    // Fill allDates with some dates. 

    // copy dates from a file: 
    std::ifstream history("plop"); 
    std::copy(std::istream_iterator<A>(history), 
       std::istream_iterator<A>(), 
       std::back_inserter(allDates) 
      ); 

    // Now save a set of dates to a file: 
    std::ofstream history("plop2"); 
    std::copy(allDates.begin(), 
       allDates.end(), 
       std::ostream_iterator<A>(history) 
      ); 
} 
+2

Je voudrais voir une comparaison de vitesse de quelque chose qui doit faire des conversions ASCII contre quelques swaps d'octets simples. Je parie que les données ASCII est encore beaucoup plus lent. – Omnifarious

+0

En fait, c'est: http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking et tandis que l'espace peut être incroyablement bon marché, la bande passante réseau et IO du disque ne l'est pas. – Omnifarious

+0

@Omnifarious: dans ce cas, vous utiliseriez des algorithmes agnostiques de plate-forme pour emballer les données et les décompresser en toute sécurité de l'autre côté. Souligner une déficience possible dans une zone localisée ne signifie pas que vous pouvez généraliser et dire «par conséquent, c'est trop lent». Gardez des problèmes dans leur domaine; Je doute sérieusement qu'il y ait des raisons de s'inquiéter de la performance ici. (Ce qui suit la même vieille directive: la correction par rapport à la performance, il est facile de faire du code correct plus rapidement, et * ça marche *.) – GManNickG

1

Vous avez raison. C'est juste un vieux morceau de données ordinaire. Pas de pointeurs drôles de table virtuelle ou quelque chose comme ça dedans.

Maintenant, je ne suis pas sûr que ce soit une bonne idée d'utiliser simplement fwrite pour écrire les données dans un fichier. Vous pouvez le faire et fread les données de retour à condition que le programme qui fait le fread est écrit avec la même version du compilateur utilisé pour faire le fwrite en premier lieu. Mais si vous changez de compilateurs, de plates-formes, ou même parfois de versions, cela peut changer.

Je suggérerais quelque chose comme Protocol Buffers pour faire le travail de rendre votre structure de données persistante.