005
12.03.2006, 12:35 Uhr
Spacelord
Hoffnungsloser Fall
|
Hi, VC++ 6 ist älter als der C++ Standard und dadurch bedingt gibt es da doch teils erhebliche Probleme mit standardkonformen Code.Sobald du mit deinem Code in "höhere" Regionen vordringst (insbesondere Templates) wirst du an die Grenzen von VC++ 6 stoßen. Es reicht sogar schon wenn du mit std::locale arbeiten willst.Da wirst du auch auf Nicht-Standard Workarounds zurückgreifen müssen.Die Liste problematischer Sprachteile lässt sich eigentlich beliebig weiterführen.....
Probier mal folgenden Code zu kompilieren(ist nur ne kleine Übung zu nem Buch das ich momentan durcharbeite,also nichts Ernstzunehmendes). checked_vector.h
C++: |
#ifndef __CHECKED_VECTOR_H #define __CHECKED_VECTOR_H
#include <vector> #include <exception>
template <class type> struct range_checker { void set_range(const type& from,const type& to) { from_ = from; to_ = to; } bool check(const type& value) { return (value >= from_ && value <= to_); } private: type from_; type to_; };
template <class type> struct no_check { bool check(const type& value){return true;} };
class illegal_value_exception:public std::exception { public: const char* what(){return "Ungueltiger Wert!";} };
template <class value_type ,template<class> class value_checker = no_check > class checked_vector:public value_checker<value_type> { public: bool insert(const value_type& value) { bool result = check(value); if(result) vec_.push_back(value); else throw illegal_value_exception();
return result; } private: std::vector<value_type> vec_; }; #endif
|
main.cpp
C++: |
#include <iostream> #include "checked_vector.h"
int main() { try { checked_vector<int> cv; cv.insert(19);
checked_vector<double,range_checker> cv2; cv2.set_range(1.2,3.4); cv2.insert(2.2); cv2.insert(4.5); }
catch(illegal_value_exception e) { std::cout<<e.what()<<std::endl; }
return 0; }
|
Vom Punkt der Standardkonformität her ist VC++ 8 ganz klar vorzuziehen!
Die Warnungen das Funktionen der (Standard) C-Runtime nicht sicher sind kannst du über nen pragma warning abstellen oder du definierst _CRT_SECURE_NO_DEPRECATE.MS hat da eigene sichere (Nicht-Standard) Funktionen ins Rennen gebracht.
Die Grösse der erzeugten Binaries hängt nicht unwesentlich von deinen Projekteinstellungen ab. Selbst die Express Edition ünterstützt die volle Optimierung der Vollversion! Habs gerade mal im Release Mode(mit Optimierung der exe Grösse /O1) folgenden Code(ist einfach hier aus dem Forum kopiert ) kompiliert.
C++: |
#include <iostream>
enum { kIsSmaller, kIsLarger, kIsSame};
// Data-Klasse für die Speicherung in der Liste. Jede // Klasse in dieser verketteten Liste muss zwei Methoden // unterstützen: Show (zeigt den Wert an) und Compare // (gibt die relative Position zurück). class Data { public: Data(int val):myValue(val){} ~Data(){} int Compare(const Data &); void Show() { std::cout << myValue << std::endl; } private: int myValue; };
// Compare entscheidet, wohin ein bestimmtes Objekt // in der Liste gehört. int Data::Compare(const Data & theOtherData) { if (myValue < theOtherData.myValue) return kIsSmaller; if (myValue > theOtherData.myValue) return kIsLarger; else return kIsSame; }
// Vorwärtsdeklarationen class Node; class HeadNode; class TailNode; class InternalNode;
// ADT, der das Knotenobjekt in der Liste darstellt. Alle // abgeleiteten Klassen müssen Insert und Show redefinieren. class Node { public: Node(){} virtual ~Node(){} virtual Node * Insert(Data * theData)=0; virtual void Show() = 0; private: };
// Dieser Knoten nimmt das eigentliche Objekt auf. // Hier hat das Objekt den Typ Data. // Bei der Behandlung von Templates wird eine // Verallgemeinerung vorgestellt. class InternalNode: public Node { public: InternalNode(Data * theData, Node * next); virtual ~InternalNode(){ delete myNext; delete myData; } virtual Node * Insert(Data * theData); virtual void Show() { myData->Show(); myNext->Show(); } // delegieren!
private: Data * myData; // die eigentlichen Daten Node * myNext; // zeigt auf nächsten Knoten in der verketteten Liste };
// Der Konstruktor führt nur Initialisierungen aus. InternalNode::InternalNode(Data * theData, Node * next): myData(theData),myNext(next) { }
// Der Kern der Listenkonstruktion. Stellt man ein // neues Objekt in die Liste, wird es an den Knoten // weitergereicht, der ermittelt, wohin das Objekt // gehört, und es in die Liste einfügt. Node * InternalNode::Insert(Data * theData) {
// Ist das neue Objekt größer oder kleiner als ich? int result = myData->Compare(*theData); switch(result) { // Ist das neue Objekt gleich groß, kommt es per Konvention vor das aktuelle. case kIsSame: // zum nächsten case-Zweig "durchfallen" case kIsLarger: // neue Daten vor mir einordnen { InternalNode * dataNode = new InternalNode(theData, this); return dataNode; }
// Größer als ich, also an den nächsten Knoten // weiterreichen. ER soll sich darum kümmern. case kIsSmaller: myNext = myNext->Insert(theData); return this; } return this; // Tribut an Compiler }
// Endeknoten ist einfach eine Markierung class TailNode : public Node { public: TailNode(){} virtual ~TailNode(){} virtual Node * Insert(Data * theData); virtual void Show() { } private: };
// Wenn Daten zu mir kommen, müssen sie vor mir eingefügt werden, // da ich der Endeknoten bin und NICHTS nach mir kommt. Node * TailNode::Insert(Data * theData) { InternalNode * dataNode = new InternalNode(theData, this); return dataNode; }
// Kopfknoten hat keine Daten, sondern zeigt einfach // auf den Beginn der Liste. class HeadNode : public Node { public: HeadNode(); virtual ~HeadNode() { delete myNext; } virtual Node * Insert(Data * theData); virtual void Show() { myNext->Show(); } private: Node * myNext; };
// Nach Erzeugen des Kopfknotens erzeugt dieser // sofort den Endeknoten. HeadNode::HeadNode() { myNext = new TailNode; }
// Vor dem Kopf kommt nichts, also die Daten einfach // an den nächsten Knoten weiterreichen Node * HeadNode::Insert(Data * theData) { myNext = myNext->Insert(theData); return this; }
// Ich stehe im Mittelpunkt, mache aber gar nichts. class LinkedList { public: LinkedList(); ~LinkedList() { delete myHead; } void Insert(Data * theData); void ShowAll() { myHead->Show(); } private: HeadNode * myHead; };
// Bei Geburt erzeuge ich den Kopfknoten. // Er erzeugt den Endeknoten. // Eine leere Liste zeigt damit auf den Kopf, dieser // zeigt auf das Ende, dazwischen ist nichts. LinkedList::LinkedList() { myHead = new HeadNode; }
// Delegieren, delegieren, delegieren void LinkedList::Insert(Data * pData) { myHead->Insert(pData); }
// Rahmenprogramm zum Testen int main() { Data * pData; int val; LinkedList ll;
// Benutzer zum Erzeugen von Werten auffordern. // Diese Werte in die Liste stellen. for (;;) { std::cout << "Welcher Wert? (0 zum Beenden): "; std::cin >> val; if (!val) break; pData = new Data(val); ll.Insert(pData); }
// Jetzt Liste durchlaufen und Daten anzeigen. ll.ShowAll(); return 0; // ll verliert Gültigkeitsbereich und wird abgebaut! }
|
Ergebnis: VC++ 8 Express Edition Release mit /O1 : 9 KB VC++ 6 Standard (keine Optimierungen verfügbar) : 140 KB !! Das ist schon nen brutaler Unterschied.....
Also wer die Wahl hat sollte sich ganz klar für VS2005 entscheiden. Ich leg mir momentan das Moos für die Professional Version an die Seite....
EDIT:Wenn du nen Win32 Projekt programmierst braucht auf der Zielplattform kein .Net Framework installiert zu sein.Du kannst da genauso native Binaries mit erstellen wie eh und je.
MfG Spacelord -- .....Ich mach jetzt nämlich mein Jodeldiplom.Dann hab ich endlich was Eigenes. Dieser Post wurde am 12.03.2006 um 12:38 Uhr von Spacelord editiert. |