Frage

Als erstes habe ich für die lange entschuldigen führen bis zu einem solchen simplen Frage.

I eine Klasse bin die Umsetzung, die auf einer Fass-Kurve oder die n-Tupel als einen sehr langen 1 dimensionalen Index repräsentiert, dient die Kartesischen Koordinaten dass Index entspricht.

class curvePoint
{
public:
    friend class curveCalculate;

    //Construction and Destruction
    curvePoint(): point(NULL), dimensions(0) {}
    virtual ~curvePoint(){if(point!=NULL) delete[] point;}

    //Mutators
    void convertToIndex(){ if(isTuple()) calc(this); }
    void convertToTuple(){ if(isIndex()) calc(this); }
    void setTuple(quint16 *tuple, int size);
    void setIndex(quint16 *index, int size);
    void setAlgorithm(curveType alg){algorithm = alg;}

    //Inspectors
    bool isIndex(){return current==Index;}
    bool isTuple(){return current==Tuple;}
    size_t size(){return dimensions;}
    quint16 operator[](size_t index);

    enum curveType{HilbertCurve, ZCurve, GrayCodeCurve};
    enum status{Index, Tuple};

private:
    curveCalculate calc;
    curveType algorithm;
    quint16 *point;
    size_t dimensions;
    status current;
};

(Die Länge des Arrays, auf dem durch Punkt ist Abmessungen )

Wie auch immer bei der Umsetzung des Operators [] Ich frage mich, was die beste Methode, die Überprüfung der Grenzen zu erreichen ist. Ich mag vermeiden, Ausnahmen zu werfen, wenn überhaupt möglich, und das gesamte Spektrum des Wertes ist für jede Zahl in der Anordnung verwendbar, um ein spezieller Wert im Fall eines außerhalb der Grenzen Fehler zurückzukehren ist nicht möglich, entweder;

Ich dachte an so etwas wie dies, obwohl in der Klassendefinition implementiert:

quint16 curvePoint::operator[](size_t index)
{
    return point[ index % dimensions ];
}

Das macht es so, dass wir nie die Grenzen des Arrays lassen und wenn sie gut dokumentiert ich denke, es wäre in Ordnung; Trotzdem bin ich Leary dieser speziellen Implementierung.

Sieht das für andere akzeptabel? Gibt es eine andere Art und Weise Grenzen zu tun, überprüft, während immer noch meine Zwänge erfüllt?

Edit: Die Berechnung der Dinge wie Hilbert-Kurven usw. sind sehr unordentlich, chaotisch genug, dass ich die zusätzliche Schnittstelle für die stl Bibliotheken in der Art und Weise nicht nicht wollen.

Darüber hinaus, weil ich will ich nicht viele Tausende dieser jedes Mal die multidimensionale Datenbank abgefragt, um konvertieren müssen die zusätzlichen Kosten der stl Funktionsaufrufe in der Mischung, wenn überhaupt möglich.

ich eher wie die Idee der Assertion; aber, wenn ich das richtig, dass Brüche in Release erinnern bauen oder nicht?

Ich glaube, ich Ausnahmen verwenden kann, die zu sein scheint, was jeder für sich Verwurzelung, aber ich die Qt-Bibliotheken verwenden und die vermeiden Ausnahmen für Leistung und Portabilität und ich habe gehofft, das gleiche zu tun.

War es hilfreich?

Lösung

Die einfachste Lösung ist als C ++ zu tun selbst tut. Dies begrenzt die Menge an Überraschungen, die Ihre Benutzer erleben werden.

C ++ selbst ist ziemlich konsistent. Sowohl die eingebaute in [] auf Zeigern und std::vector::operator[] haben nicht definiertes Verhalten, wenn Sie verwenden, um eine out-of-gebundenen Array-Index. Wenn Sie die Überprüfung der Grenzen wollen, werden explizite und verwenden std::vector::at

Wenn Sie also das gleiche für Ihre Klasse zu tun, können Sie das Out-of-gebundene Verhalten als „Standard“ dokumentieren.

Andere Tipps

  

Wie auch immer bei der Umsetzung der   operator [] Ich habe mich gefragt, was die   beste Methode zu erreichen, die Überprüfung der Grenzen   ist. Ich möchte Werfen vermeiden   Ausnahmen, wenn überhaupt möglich, und die   vollständige Palette von Werten ist verwendbar für   Jede Zahl in der Anordnung so eine spezielle   Wert zurück im Fall eines aus   Grenzen Fehler ist nicht möglich, entweder;

Dann werden die restlichen Optionen sind:

  • Flexibles Design. Was Sie getan haben. „Fix“ die ungültige Eingabe, so dass er versucht, etwas zu tun, was Sinn macht. Vorteil: Funktion wird nicht abstürzen. Nachteil: Clueless Anrufer, die einen außerhalb der Grenzen Element zugreifen erhalten eine Lüge als Ergebnis. Stellen Sie sich ein 10-stöckiges Gebäude mit Etagen 1 bis 10:
  

Sie: "Wer wohnt im 3. Stock"

     

Me: "Mary"

.      

Sie: "Wer wohnt in der 9. Etage"

     

Me: "Joe"

.      

Sie: "Wer wohnt in der 1,203rd Etage"

     

Ich: (Wait ... 1203% 10 = 3, ...)   > "Mary" .

     

Sie: "Wow, muss Mary tolle Aussicht vom genießen . So besitzt sie zwei Wohnungen dann? "

  • Bool Ausgangsparameter zeigt Erfolg oder Misserfolg. Diese Option endet in der Regel in nicht sehr verwendbaren Code auf. Viele Anwender werden den Return-Code ignorieren. Sie sind immer noch links mit dem, was man in dem anderen Rückgabewert zurück.

  • Design by Contract. Behaupten, dass der Anrufer innerhalb von Grenzen ist. (Für einen praktischen Ansatz in C ++ finden Sie unter eine Ausnahme oder einen Fehler? Von Miro Samek oder Einfache Unterstützung für Design by Contract in C ++ von Pedro Guerreiro .)

  • Zurück a System.Nullable<quint16> . Hoppla, warten, das ist nicht C #. Nun, man könnte einen Zeiger auf eine quint16 zurückzukehren. Das hat natürlich viele Auswirkungen auf die ich hier nicht diskutieren, und die diese Option wahrscheinlich machen nicht verwendet werden.

Meine Lieblings-Auswahl sind:

  • Für die öffentliche Schnittstelle einer öffentlich freigegeben Bibliothek: Eingabe wird geprüft und eine Ausnahme wird geworfen werden. Sie entschieden, diese Option aus, so ist es keine Option für Sie. Es ist immer noch mein Wahl für die Schnittstelle einer öffentlich freigegeben Bibliothek.
  • für den internen Code:. Entwurf durch Vertrag

Für mich ist diese Lösung nicht akzeptabel, weil sie eine sehr harte verstecken kann Fehler zu finden. ein außerhalb des zulässigen Bereichs Ausnahme werfen wird, um den Weg zu gehen, oder zumindest eine Aussage in der Funktion setzen.

Wenn das, was Sie brauchen eine Art „Rundschreiben“ Anordnung von Punkten ist, dann Ihre Lösung ist in Ordnung. Doch mir, es sieht aus wie missusage des Indizierungsoperators hinter einer „sicheren“ Logik versteckt, so würde ich gegen Ihre vorgeschlagene Lösung sein.

Wenn nicht will Index Überlauf ermöglichen, dann könnten Sie überprüfen und eine Ausnahme aus.

quint16 curvePoint::operator[](size_t index)
{
    if( index >= dimensions)
    {
       throw std::overflow_error();
    }
    return point[ index ];
}

Wenn Sie weniger Aufwand haben wollen, können Sie Ausnahme vermeiden, indem Debug-Zeit Behauptungen verwendet (unter der Annahme, dass der bereitgestellte Index immer gültig ist):

quint16 curvePoint::operator[](size_t index)
{
    assert( index < dimensions);
    return point[ index ];
}

Allerdings schlage ich vor, dass anstelle Punkt und Dimensionselemente zu verwenden, verwenden Sie eine std :: vector für Punkt Lagerung. Es hat bereits einen Index basierten Zugriff, die Sie verwenden können:

quint16 curvePoint::operator[](size_t index)
{
    // points is declared as std::vector< quint16> points;
    return points[ index ];
}

Mit einem Operator [], die nie klingt gut ausfällt, kann aber Fehler versteckt später, wenn eine rufende Funktion verwendet ein illegales Offset findet einen Wert aus dem Anfang des Puffers und geht als ob das ein gültiger Wert ist.

Die beste Methode, die Überprüfung der Grenzen zu erreichen, wäre eine Assertion hinzuzufügen.

quint16 curvePoint::operator[](size_t index)
{
    assert(index < dimensions);
    return point[index];
}

Wenn Ihr Code hängt bereits auf Boost-Bibliotheken, möchten Sie vielleicht stattdessen BOOST_ASSERT verwenden.

Wenn ich Sie wäre, würde ich das Beispiel folgen der stl gesetzt.

In diesem Fall std::vector liefert zwei Methoden: at die Grenzen geprüft und operator[] ist das nicht der Fall ist. Dies ermöglicht es der Client mit Version zu entscheiden, zu verwenden. Ich würde auf jeden Fall nicht den % size() verwenden, da dies nur den Fehler versteckt. Jedoch eine Menge Aufwand fügt die Überprüfung der Grenzen für, wenn sie über eine große Sammlung iterieren, deshalb ist es optional sein sollte. Obwohl ich mit anderen Plakaten einverstanden ist, dass die Assertion eine sehr gute Idee, da dies nur ein Performance-Problem in Debug-Builds.

Sie sollten auch zurückkehr Referenzen und liefert const und nicht const Versionen betrachten. Hier sind die Funktionsdeklarationen für std::vector :

reference at(size_type _Pos);
const_reference at(size_type _Pos) const;

reference operator[](size_type _Pos);
const_reference operator[](size_type _Pos) const;

Als gute Faustregel gilt: wenn ich nicht sicher bin, wie ein API mich für Beispiele aussehen angeben, wie andere ähnliche APIs angeben. Auch wenn immer ich eine API verwenden, ich versuche, es zu beurteilen oder zu bewerten, findet die Bits Ich mag und nicht mag.

Dank der Kommentar auf der C # Funktion in der Post von Daniel Daranas Ich habe es geschafft, eine mögliche Lösung herauszufinden. Wie ich in meiner Frage habe ich festgestellt, die Qt-Bibliotheken verwenden. Dort kann ich QVariant verwenden. QVariant kann auf einen ungültigen Zustand gesetzt werden, der durch die Funktion überprüft werden kann es zu empfangen. So würde der Code so etwas wie sein:

QVariant curvePoint::operator[](size_t index){
    QVariant temp;
    if(index > dimensions){
        temp = QVariant(QVariant::Invalid);
    }
    else{
        temp = QVariant(point[index]);
    }

    return temp;
}

Dies ist natürlich das Potenzial hat, der ein wenig knorrigen Kopf in die Funktion eingefügt, so eine andere Möglichkeit ist ein Paar Vorlage zu verwenden.

std::pair<quint16, bool> curvePoint::operator[](size_t index){
    std::pair<quint16, bool> temp;
    if(index > dimensions){
        temp.second = false;
    }
    else{
        temp.second = true;
        temp.first = point[index];
    }
    return temp;
}

Oder ich könnte eine QPair verwenden, die genau die gleiche Funktionalität hat und würde es so machen, dass die STL nicht verknüpft werden müssen.

Sie könnten vielleicht eine „außerhalb der Grenzen“ Ausnahme von dem Operator [] (oder zumindest eine Assertion).

hinzufügen

Dies sollte keine Probleme fangen, vor allem bei der Fehlersuche.

Es sei denn, ich bin etwas drastisch Missverständnis,

return point[ index % dimensions ];

gar nicht Grenzen überprüft. Es ist ein echter Wert aus einem völlig anderen Teil der Strecke zurückkehrt, die es viel schwieriger zu erkennen Fehler machen wird.

Ich würde entweder:

  1. Werfen Sie eine Ausnahme oder eine Assertion (obwohl Sie sagten, Sie wollen nicht tun)
  2. Simply dereferenzieren Punkt hinter dem Array in einem „natürlichen“ Weg (das heißt überspringt nur jede interne Kontrolle). Der Vorteil gegenüber dem% ist, dass sie eher sind (obwohl nicht definiert nicht definiert ist) „weird“ Werte zu erhalten und / oder eine Zugriffsverletzung

Am Ende wird der Anrufer Ihre Voraussetzungen zu verletzen, und Sie können tun, was Sie wollen. Aber ich denke, das sind die meisten vernünftigen Optionen.

Beachten Sie auch, was gesagt Cătălin über die Einbeziehung der Sammlungen eingebaute in STL, wenn das ist vernünftig.

Ihre Lösung wäre schön, wenn Sie Zugriff auf die Punkte einer elliptischen Form bereitgestellt wurden. Aber es wird zu sehr fiesen Bugs führen, wenn Sie es für beliebige geometrische Funktionen verwenden, da Sie wissentlich einen falschen Wert liefern.

Der Modulo-Operator funktioniert überraschend gut für Array-Indizes - es führt auch negativen Indizes (dh point[-3] = point[dimensions - 3].). Dies ist leicht zu verarbeiten, also würde ich persönlich den Modulo-Operator, so lange empfehlen, da es gut dokumentiert.

Eine weitere Option ist der Anrufer wählt die out-of-bounds Politik zu lassen. Bedenken Sie:

template <class OutOfBoundsPolicy>
quint16 curvePoint::operator[](size_t index)
{
    index = OutOfBoundsPolicy(index, dimensions);
    return point[index];
}

Dann könnten Sie mehrere Richtlinien definieren, die der Anrufer wählen kann. Zum Beispiel:

struct NoBoundsCheck {
    size_t operator()(size_t index, size_t /* max */) {
        return index;
    }
};

struct WrapAroundIfOutOfBounds {
    size_t operator()(size_t index, size_t max) {
        return index % max;
    }
};

struct AssertIfOutOfBounds {
    size_t operator()(size_t index, size_t max) {
        assert(index < max);
        return index % max;
    }
};

struct ThrowIfOutOfBounds {
    size_t operator()(size_t index, size_t max) {
        if (index >= max) throw std::domain_error;
        return index;
    }
};

struct ClampIfOutOfBounds {
    size_t operator()(size_t index, size_t max) {
        if (index >= max) index = max - 1;
        return index;
    }
};
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top