Unterschied zwischen "const shared_ptr <T>" und "shared_ptr <const T>"?

115

Ich schreibe eine Zugriffsmethode für einen gemeinsam genutzten Zeiger in C ++, die ungefähr so ​​aussieht:

class Foo {
public:
    return_type getBar() const {
        return m_bar;
    }

private:
    boost::shared_ptr<Bar> m_bar;
}

Um die Konstanz des getBar()Rückgabetyps zu unterstützen, sollte ein Wert verwendet werden boost::shared_ptr, der eine Änderung des Zeigertyps verhindert Bar. Ich vermute, dass dies shared_ptr<const Bar>der Typ ist, zu dem ich zurückkehren möchte, während const shared_ptr<Bar>dies eine Neuzuweisung des Zeigers selbst verhindern würde, um auf einen anderen zu zeigen, Baraber eine Änderung des Zeigers zulässt, auf den Barer zeigt ... Ich bin mir jedoch nicht sicher. Ich würde es begrüßen, wenn jemand, der es genau weiß, dies entweder bestätigen oder mich korrigieren könnte, wenn ich etwas falsch gemacht hätte. Vielen Dank!

Dave Lillethun
quelle
3
Genau das hast du gesagt. Sie können die Dokumentation für Bediener einsehen *und dies ->bestätigen.
Syam
2
Was ist der Unterschied zwischen T *constund T const *? Das Gleiche.
3
@ H2CO3 Überhaupt nicht. Das conständert normalerweise, was _preced es ist, T *constist also ein constZeiger auf Tund T const*ist ein Zeiger auf const T. Und es ist am besten zu vermeiden, constmit nichts davor zu verwenden.
James Kanze
6
@ JamesKanze, das ist der Punkt von H2CO3: Der Unterschied zwischen T *constund T const *ist der gleiche wie der Unterschied zwischen const shared_ptr<T>undshared_ptr<const T>
Jonathan Wakely
1
@ JamesKanze Oh aber ja. T *constein const Zeiger auf nicht-const ist T, so ist const shared_ptr<T>. Im Gegensatz dazu T const *ist eine nicht-const Zeiger auf const T, so ist shared_ptr<const T>.

Antworten:

176

Du hast recht. shared_ptr<const T> p;ist ähnlich const T * p;(oder gleichwertig T const * p;), das heißt, das spitze Objekt ist, constwährend const shared_ptr<T> p;es ähnlich ist, T* const p;was bedeutet, dass das pheißt const. Zusammenfassend:

shared_ptr<T> p;             ---> T * p;                                    : nothing is const
const shared_ptr<T> p;       ---> T * const p;                              : p is const
shared_ptr<const T> p;       ---> const T * p;       <=> T const * p;       : *p is const
const shared_ptr<const T> p; ---> const T * const p; <=> T const * const p; : p and *p are const.

Gleiches gilt für weak_ptrund unique_ptr.

Cassio Neri
quelle
1
Sie haben auch eine Frage beantwortet, die ich im Hinterkopf zu regulären Zeigern hatte (const T * vs. T * const vs. T const *). :) Ich habe das nicht erwähnt, weil ich nicht wollte, dass meine Frage zu SO zu weit gefasst ist , und dies war die Frage, die für meine aktuelle Aufgabe relevant war. Jedenfalls denke ich, dass ich jetzt sehr gut verstehe. Vielen Dank!
Dave Lillethun
9
Ich bin froh, dass es geholfen hat. Ein letzter Tipp, an den ich mich erinnere const T* p;', 'T const * p;und an den ich mich erinnere T * const p. Sehen Sie das *als Trennzeichen in dem Sinne, dass das, was ist, das constist, was sich auf derselben Seite des befindet *.
Cassio Neri
5
Meine Faustregel lautet, dass sich das constimmer auf das Ding auf der linken Seite bezieht. Wenn links nichts ist, ist es das Ding auf der rechten Seite.
hochl
hochi - wie wäre es mit const T * p; äquivalent zu T const * p;?
Vlad
Cassio, Sie können hinzufügen, dass im Fall des zurückgegebenen Typs const shared_ptr <T> diese nicht in Nicht-const-Funktionen verwendet werden kann, während dies für const-Zeiger nicht gilt.
Vlad
2

boost::shared_ptr<Bar const>verhindert die Änderung des BarObjekts durch den gemeinsam genutzten Zeiger. Als Rückgabewert boost::shared_ptr<Bar> constbedeutet const in , dass Sie für das zurückgegebene temporäre Element keine Nicht-const-Funktion aufrufen können. wenn es für einen echten Zeiger wäre (zBar* const ), würde er vollständig ignoriert.

Im Allgemeinen gelten auch hier die üblichen Regeln: constÄndert, was davor steht: in boost::shared_ptr<Bar const>, the Bar; in boost::shared_ptr<Bar> constist es die Instanziierung (der Ausdruck, boost::shared_ptr<Bar>der const ist.

James Kanze
quelle
1
@ Gatopeich So kannst du deletees.
Marcin
@Marcin könnten Sie ausarbeiten?
Gatopeich
1
#Check this simple code to understand... copy-paste the below code to check on any c++11 compiler

#include <memory>
using namespace std;

class A {
    public:
        int a = 5;
};

shared_ptr<A> f1() {
    const shared_ptr<A> sA(new A);
    shared_ptr<A> sA2(new A);
    sA = sA2; // compile-error
    return sA;
}

shared_ptr<A> f2() {
    shared_ptr<const A> sA(new A);
    sA->a = 4; // compile-error
    return sA;
}

int main(int argc, char** argv) {
    f1();
    f2();
    return 0;
}
vivek2k6
quelle
Darf ich die Verwendung von std::make_shared()(seit C ++ 14) vorschlagen .
Joel Bodenmann
0

Ich möchte eine einfache Demostration basierend auf der Antwort von @Cassio Neri:

#include <memory>

int main(){
    std::shared_ptr<int> i = std::make_shared<int>(1);
    std::shared_ptr<int const> ci;

    // i = ci; // compile error
    ci = i;
    std::cout << *i << "\t" << *ci << std::endl; // both will be 1

    *i = 2;
    std::cout << *i << "\t" << *ci << std::endl; // both will be 2

    i = std::make_shared<int>(3);
    std::cout << *i << "\t" << *ci << std::endl; // only *i has changed

    // *ci = 20; // compile error
    ci = std::make_shared<int>(5);
    std::cout << *i << "\t" << *ci << std::endl; // only *ci has changed

}
Jónás Balázs
quelle