Різниця між `const shared_ptr <T>` та `shared_ptr <const T>`?


116

Я пишу метод аксесуара для спільного вказівника на C ++, який виглядає приблизно так:

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

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

Отже, для підтримки константності getBar()повернення типу повинно бути таке, boost::shared_ptrщо не дозволяє модифікувати Barйого, на які вказує. Я здогадуюсь , що shared_ptr<const Bar>саме до цього типу я хочу повернутися, тоді як const shared_ptr<Bar>перешкоджатиме переназначенню самого вказівника вказувати на інше, Barале допускати модифікацію того, на Barщо вказує ... Однак я не впевнений. Буду вдячний, якщо хтось, хто знає напевно, міг би це підтвердити, або виправити мене, якщо я помилився. Дякую!


3
Це саме те, що ви сказали. Ви можете переглянути документацію для операторів *і ->підтвердити це.
syam

2
Яка різниця між T *constі T const *? Так само.

3
@ H2CO3 Зовсім не. В constзазвичай модифікує , що _precedes, тому T *constє constпокажчиком T, і T const*є покажчиком const T. І краще уникати використання, constне передуючи цьому.
Джеймс Канзе

6
@JamesKanze, це точка H2CO3: різниця між T *constі T const *така ж, як різниця між const shared_ptr<T>іshared_ptr<const T>
Джонатан Уейклі

1
@JamesKanze О, але так. T *constє вказівником const на non-const T, так і є const shared_ptr<T>. Навпаки, T const *це неконст-покажчик на const T, так і є shared_ptr<const T>.

Відповіді:


176

Ти правий. shared_ptr<const T> p;аналогічно const T * p;(або, що те ж саме, T const * p;), тобто, загострений об'єкт , constтоді як const shared_ptr<T> p;аналогічна T* const p;це означає , що pє const. Підсумовуючи:

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.

Те саме стосується weak_ptrі unique_ptr.


1
Ви також відповіли на запитання, яке у мене було в задній частині голови щодо регулярних покажчиків (const T * vs. T * const vs. T const *). :) Я цього не згадував, тому що не хотів, щоб моє запитання щодо SO було занадто широким, і це питання стосувалося мого поточного завдання. Як би там не було, я думаю, що зараз це дуже добре розумію. Дякую!
Дейв Ліллетун

9
Я радий, що це допомогло. Остання порада, яку я використовую, щоб згадати про const T* p;', 'T const * p;і T * const p. Побачити *як роздільник у тому сенсі, що constє те, що є на тій же стороні *.
Кассіо Нері

5
Моє правило - це те, що constзавжди стосується речі з лівої сторони. Якщо зліва немає нічого, це справа з правого боку.
hochl

hochi - як щодо const T * p; еквівалентно T const * p ;?
Влад

Кассіо, ви можете додати, що у випадку повернутого типу const shared_ptr <T> він не може бути використаний у функціях non-const, поки це не відповідає правилам покажчиків const.
Влад

2

boost::shared_ptr<Bar const>запобігає модифікації Barоб'єкта через загальний покажчик. Як повернене значення, const boost::shared_ptr<Bar> constозначає, що ви не можете викликати функцію non-const на поверненій тимчасовій; якби це був справжній покажчик (напрBar* const ), він був би повністю проігнорований.

Взагалі навіть тут діють звичайні правила: constмодифікує те, що йому передує: in boost::shared_ptr<Bar const>, the Bar; в boost::shared_ptr<Bar> const, це інстанція (вираз, boost::shared_ptr<Bar>який є const.


1
@gatopeich Так ви можете delete.
Марцін

@Marcin ви могли б розвинути?
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;
}

Можна запропонувати використовувати std::make_shared()(оскільки C ++ 14).
Джоель Боденман

0

Я хотів би просту демонстрацію на основі відповіді @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

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.