Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

TrommlBomml

Community-Fossil

  • »TrommlBomml« ist der Autor dieses Themas

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

1

25.02.2014, 08:46

C++ best practice: Umgang mit Collections in öffentlichen Schnittstellen

Hallo Zusammen,

ich habe diesmal eine Frage, wie ihr so in C++ mit dem Thema umgeht, wenn Collections (vector, list, map) nach außen gegeben werden. Ich gehe in meine Fall davon aus, dass das herausgeben notwendig ist, weil die herauszugebende Liste verarbeitet werden kann (sortieren und iterieren).
Es gibt verschiedene Ansätze, wobei ich mir nicht ganz sicher bin, welcher ein guter Weg ist:

1) Kopie des Vektors herausgeben
2) Referenz des Vektors herausgeben
3) Zeiger auf den Vektor herausgeben
4) Iteratoren für Beginn und Ende des Vektors herausgeben
5) Iterieren in der Klasse durch Methoden verankern, die den Vektor bereitstellt.

Schade finde ich eigentlich, dass es da in C++ keine eigenen Interfaces wie IEnumerable, ICollection oder IList gibt. Dadurch kann man wunderbar nach außen den Funktionsumfang beschränken.

Wie geht ihr damit um und was findet ihr ist gute Praxis? Ich tendiere ja aus Einfachheitsgründen zu Punkt 2.

DeKugelschieber

Community-Fossil

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

2

25.02.2014, 13:28

C-/C++-Quelltext

1
const std::vector<int>& getInts();


Mache ich.
Es kommt aber darauf an was mit den Daten möglich sein soll. Oft dann noch dieser Fall:

C-/C++-Quelltext

1
2
3
4
5
6
7
int getInt(const unsigned int index){
    if(index < ints.size()){
        return ints[index];
    }

    return 0; // oder so
}


Wenn ich davon ausgehe das nur einzelne Werte geholt werden. Außerdem kann man dann natürlich noch Überprüfungen in der Methode vornehmen...

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

3

25.02.2014, 13:45

Deine zweite Variante wird in den meisten Fällen wohl nicht so gut sein. Es sei denn 0 wäre in dem Fall kein valider Wert in deiner Collection. Am besten man wirft hier einfach eine Exception. Damit ist man immer auf der sicheren Seite. Auch wenn sich der Wertebereich der Collection ändert. Auch wenn das hier sicherlich nur ein Beispiel von dir war.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

4

25.02.2014, 14:11

Ich gebe in solchen Fällen gerne eine Iterator Range zurück. Also so etwas in der Art:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
template <typename Iterator>
class Range {
    public:
        Range(Iterator begin, Iterator end);
        auto begin() const -> Iterator;
        auto end() const -> Iterator;
    private:
        Iterator m_begin, m_end;
};

Das lässt sich bei Bedarf dann auch prima in range-based for Loops benutzen.

Ich habe aber auch schon mit der Möglichkeit geliebäugelt, foreach-Methoden für das Iterieren über private Container anzubieten:

C-/C++-Quelltext

1
2
3
4
5
class World {
    public:
        void forEachTown(std::function<void(Town&)>);
        void forEachVillage(std::function<void(Village&)>);
}

Beide Methoden könnten hier auf demselben Container operieren, ihn aber unterschiedlich filtern. Allerdings habe ich so etwas bisher noch nicht benötigt.

Tankard

Treue Seele

Beiträge: 192

Beruf: Student, Hardware- und Softwareentwicklung als wissenschaftliche Hilfskraft

  • Private Nachricht senden

5

25.02.2014, 14:19

Kurze Zwischenfrage meinerseits.
Die Zeile

Quellcode

1
auto begin() const -> Iterator;

ist diese Notation äquivalent zu

Quellcode

1
Iterator begin() const;

oder gibt es da wirkliche Unterschiede?

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

6

25.02.2014, 15:46

Ich frag mich in solchen Fällen immer erst einmal, wieso genau die Collection im Interface exposed werden sollte, denn meistens ist so eine Collection meiner Erfahrung nach eher ein Implementierungsdetail, welches besser nicht nach draußen geht. Anstatt den internen vector weiterzureichen, damit andere drüber iterieren können, sollte nicht besser das Iterieren etc. Methode des Besitzers der Collection sein?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »dot« (25.02.2014, 15:52)


Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

7

25.02.2014, 15:53

Das spricht TrommlBomml doch selbst an? Es gibt kein IEnumerable etc weshalb er doch hier nach Alternativen fragt. Gut er beschränkt sich bei seiner Frage ein wenig auf den Rückgabetyp, aber ich denke andere Antworten helfen ihm auch weiter.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

8

25.02.2014, 15:53

@Tankard

Das macht beides das Gleiche. Die obere Form ist der alternative Funktionssyntax, der mit C++11 eingeführt wurde.
Der alternative Syntax erlaubt es unter anderem, auf die Funktionsparameter Bezug zu nehmen:

C-/C++-Quelltext

1
2
3
4
template <typename Factory>
auto buildObject(const Factory& factory) -> decltype(factory.build()) {
    return factory.build();
}

Na ja, wohl nicht das beste Beispiel, aber man sieht hoffentlich trotzdem, was man vom Prinzip her damit anstellen kann.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

9

25.02.2014, 16:55

Das spricht TrommlBomml doch selbst an? Es gibt kein IEnumerable etc weshalb er doch hier nach Alternativen fragt. Gut er beschränkt sich bei seiner Frage ein wenig auf den Rückgabetyp, aber ich denke andere Antworten helfen ihm auch weiter.

IEnumerable tut ebenfalls nichts Anderes, als die Tatsache, dass es unter der Haube eine Collection gibt, nach außen zu tragen. Außerdem ist es nicht effizient... ;)

DeKugelschieber

Community-Fossil

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

10

25.02.2014, 19:46

@Schorsch: klar, exceptions schmeißen wäre dort meistens sinnvoller. Hier war das nur ein Beispiel.

Werbeanzeige