Const Correctness
-
Hallo Forum,
in OpenCV gibt es die Klasse cv::Mat, die unter anderem ein Bild repräsentieren kann. Copy-Constructor und Zuweisungsoperator der Klasse sind so gestaltet, dass der eigentliche Bildinhalt nicht kopiert wird sondern nur die übrigen Member.
cv::Mat foo(cv::imread(R"(C:\myImg.png)"); // Bild laden cv::Mat bar(foo); // "Kopie" erzeugen cv::circle(bar, cv::Point(30, 30), 5, CV_RGB(255, 0, 0)); // Kreis in bar zeichnen -> ändert (auch) foo
Nehmen wir an, ich habe eine Klasse, die ein cv::Mat Member hat und die ich mit einem entsprechenden Getter ausrüsten möchte:
struct Foo { Foo(const std::string& imgPath) : m_img(cv::imread(imgPath)) {} const cv::Mat& GetMat() const { return m_img; } // wie sollte die Signatur dieses Getters aussehen? private: cv::Mat m_img; }; Foo foo(R"(C:\myImg.png)"); auto bar = foo.GetMat(); cv::circle(bar, cv::Point(30, 30), 5, CV_RGB(255, 0, 0)); // Kreis in bar zeichnen -> ändert Foo::m_image
Meine Frage ist, wie ihr GetMat() implementieren würdet.
const cv::Mat& GetMat() const // ist diese Methode const, obwohl außerhalb schreibend auf das Member zugegriffen werden kann? const cv::Mat& GetMat() // zwar nicht mehr const, verbirgt aber, dass eine Kopie der zurückgegebenen const-Referenz Zugriff auf das Member ermöglicht cv::Mat& GetMat() // vielleicht die einzig konsequente Variante? Jedenfalls mein Favorit.
Über ein paar Anregungen und Kommentare zu den drei Varianten würde ich mich freuen.
-
const cv::Mat& GetMat() const
Ich verstehe gar nicht, warum du den getter ändern willst, weil sich irgendeine Funktion -auf die du keinen Einfluss hast- sich merkwürdig verhält.
-
Dein Vorschlag wäre also, dass ich die "Innereien" von cv::Mat einfach ignoriere und den Getter so implementiere wie ich es üblicherweise machen würde.
Der Argumentation kann ich schon folgen, wenn man aber ein bisschen allgemeiner denkt, gefällt mir halt nicht, dass ich in einer Klasse eine const-Methode anbiete, die eine Änderung der Member ermöglicht. Thread-Safety ist in meinem konkreten Fall zwar kein Thema, aber const-Methoden werden beispielsweise gerne mal mit Thread-Safety assoziiert und solche Dinge würde ich auf diese Art wissentlich "verschleiern"...
-
Und von einer Kopie würde man erwarten, dass sie eine Kopie macht…
Wenn Open_CV ein Objekt als unverändert ansieht, solange sich die Hilfsdaten nicht ändern, die eigentlichen Nutzdaten aber schon, würde ich diese Semantik an deiner Stelle auch so weiter geben. Die merkwürdige Semantik kommt hier nicht von deiner Klasse.
-
Du hast ein Paar Möglichkeiten.
- Den Getter irgendeine Form von
Mat
zurückgeben lassen. Wenn es für die interne Logik der Klasse zählt, dassm_img
nicht modifiziert wird, offensichtlich nicht mitconst
qualifizieren. Dasconst
an der Referenz kannste ruhig lassen. Vielleicht einen entsprechenden Kommentar über der Deklaration stehen lassen. - Einen Wrapper schreiben. Das kann sowohl ein funktional vollständiger Wrapper sein (sprich,
Mat
komplett anbieten, aber Kopier-Semantik kohärent gestalten), oder einfach eine immutable view. Mit der letzteren Idee wären wir auch bei der nächsten angelangt: - Die Getter von
Mat
anbieten. Falls die Meta-Informationen inMat
für die Nutzer vonGetMat
nicht von Bedeutung sind, sondern lediglich der Inhalt, kannst Du sie auch unmittelbar auf den Inhalt zugreifen lassen. Ist Design-technisch etwas unschöner aber immerhin sauber. - Klage vor dem Bundesgerichtshof die
const
Correctness der Bibliothek ein.
- Den Getter irgendeine Form von
-
Vielen Dank für die Anregungen!
Ich denke, dann werde ich euch folgen und nicht die OpenCV-Eigenheiten zu meinen eigenen machen. Wenn man das entsprechend kommentiert, sollte dem Anwender ja auch klar werden, wie damit umzugehen ist.
Columbos vierten Punkt lasse ich mich auch noch einmal durch den Kopf gehen .