Differenza tra "const shared_ptr <T>" e "shared_ptr <const T>"?


116

Sto scrivendo un metodo di accesso per un puntatore condiviso in C ++ che funziona in questo modo:

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

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

Quindi per supportare la costanza del getBar()tipo restituito dovrebbe essere un boost::shared_ptrche impedisce la modifica del Barpunto a cui punta. La mia ipotesi è che shared_ptr<const Bar>sia il tipo a cui voglio tornare per farlo, mentre const shared_ptr<Bar>impedirebbe la riassegnazione del puntatore stesso in modo che punti a un diverso Barma consentirebbe la modifica del Barpunto a cui punta ... Tuttavia, non ne sono sicuro. Apprezzerei se qualcuno che lo sa con certezza potesse confermarlo o correggermi se ho sbagliato. Grazie!


3
È esattamente quello che hai detto. Puoi guardare la documentazione per gli operatori *e ->confermarlo.
Syam

2
Qual è la differenza tra T *conste T const *? Lo stesso.

3
@ H2CO3 Niente affatto. Le constnormalmente modifica quello _precedes, quindi T *constè un constpuntatore T, e T const*è un puntatore a const T. Ed è meglio evitare di utilizzare constcon nulla che lo preceda.
James Kanze

6
@JamesKanze, questo è il punto di H2CO3: la differenza tra T *conste T const *è uguale alla differenza tra const shared_ptr<T>eshared_ptr<const T>
Jonathan Wakely

1
@JamesKanze Oh ma sì. T *constè un puntatore const a non-const T, così è const shared_ptr<T>. Al contrario, T const *è un puntatore non const const T, così è shared_ptr<const T>.

Risposte:


176

Hai ragione. shared_ptr<const T> p;è simile a const T * p;(o, equivalentemente, T const * p;), cioè l'oggetto appuntito è constmentre const shared_ptr<T> p;è simile a T* const p;che significa che pè const. In sintesi:

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.

Lo stesso vale per weak_ptre unique_ptr.


1
Hai anche risposto a una domanda che avevo nella parte posteriore della mia testa sui puntatori regolari (const T * vs T * const vs T const *). :) Non l'ho detto perché non volevo che la mia domanda su SO fosse troppo ampia, e questa era la domanda pertinente al mio compito attuale. Comunque, penso di capire molto bene ora. Grazie!
Dave Lillethun

9
Sono contento che abbia aiutato. Un ultimo consiglio che uso per ricordare const T* p;', 'T const * p;e T * const p. Vedi il *separatore nel senso che cos'èconst è ciò che è dalla stessa parte del *.
Cassio Neri

5
La mia regola pratica è che constsi riferisce sempre alla cosa sul lato sinistro di esso. Se nulla è a sinistra, è la cosa a destra.
hochl

hochi: che ne dici di const T * p; equivalente a T const * p ;?
Vlad

Cassio, puoi aggiungere che nel caso del tipo restituito const shared_ptr <T>, non può essere utilizzato in funzioni non const mentre questo non è vero per i puntatori const.
Vlad il

2

boost::shared_ptr<Bar const>impedisce la modifica Bardell'oggetto tramite il puntatore condiviso. Come valore di ritorno, const in boost::shared_ptr<Bar> constsignifica che non è possibile chiamare una funzione non const sul temporaneo restituito; se fosse per un puntatore reale (ad esempio Bar* const), sarebbe completamente ignorato.

In generale, anche qui valgono le solite regole: const modifica ciò che lo precede: in boost::shared_ptr<Bar const>, the Bar; in boost::shared_ptr<Bar> const, è l'istanziazione (l'espressione boost::shared_ptr<Bar>che è const.


1
@gatopeich Quindi puoi deletefarlo.
Marcin

@ Marcin potresti ellaborate?
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;
}

Posso suggerire l'uso di std::make_shared()(da C ++ 14).
Joel Bodenmann

0

Vorrei una semplice dimostrazione basata sulla risposta di @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

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.