Правильность константы интеллектуального указателя C++

У меня есть несколько контейнеров в классе, например, векторе или карте, которые содержат shared_ptr к объектам, живущим на "куче".

Например,

template <typename T>
class MyExample
{
public:

private:
    vector<shared_ptr<T> > vec_;
    map<shared_ptr<T>, int> map_;
};

Я хочу иметь открытый интерфейс этого класса, который иногда возвращает shared_ptrs объектам константы (через shared_ptr<const T>) и иногда shared_ptr<T> где я позволяю вызывающей стороне видоизменять объекты.

Я хочу логическую правильность константы, поэтому если я отмечаю метод как константу, она не может изменить объекты на "куче".

Вопросы:

1) Я смущен взаимозаменяемостью shared_ptr<const T> и shared_ptr<T>. Когда кто-то передает a shared_ptr<const T> в класс сделайте меня:

  • Сохраните его как a shared_ptr<T> или shared_ptr<const T> в контейнере?
  • ИЛИ
  • Сделайте я изменяю карту, типы векторов (например, insert_element (shared_ptr<const T> obj)?

2) Лучше инстанцировать классов следующим образом: MyExample<const int>? Это кажется незаконно строгим, потому что я никогда не могу возвращать a shared_ptr<int>?

42
задан Daniel Trugman 7 August 2019 в 14:09
поделиться

4 ответа

Если кто-то передаст вам shared_ptr, вы никогда не сможете изменить T. Конечно, технически возможно передать const T только T, но это нарушает намерение сделать T const. Так что если вы хотите, чтобы люди могли добавлять объекты в ваш класс, они должны дать вам shared_ptr и не shared_ptr. Когда вы возвращаете вещи из своего класса, которые не хотите изменять, то есть когда вы используете shared_ptr.

shared_ptr может быть автоматически преобразован (без явного кастинга) в shared_ptr, но не наоборот. Это может помочь вам (и вы должны это сделать в любом случае) либерально использовать методы const. Когда вы определяете метод класса const, компилятор не позволит модифицировать ни один из ваших членов данных или возвращать что-либо, кроме const T. Таким образом, использование этих методов поможет вам убедиться, что вы ничего не забыли, и поможет пользователям вашего класса понять, в чем смысл этого метода. (Пример: virtual shared_ptr myGetSharedPtr(int index) const;)

Вы правы во втором утверждении, скорее всего, Вы не хотите инстанцировать Ваш класс как , так как никогда не сможете модифицировать ни один из Ваших T.

6
ответ дан 26 November 2019 в 23:54
поделиться

Одно можно понять, что:

Tr1 :: Shared_ptr имитирует функциональность t const * , а именно то, что он указывает на Const, но сам указатель нет.

Итак, вы можете назначить новое значение вашему общему указателю, но я ожидаю, что вы не сможете использовать ReareFerection Shared_PTR в качестве L-значение.

3
ответ дан 26 November 2019 в 23:54
поделиться

Я бы предложил бы следующую мемотологию:

template <typename T>
class MyExample
{
  private:
    vector<shared_ptr<T> > data;

  public:
    shared_ptr<const T> get(int idx) const
    {
      return data[idx];
    }
    shared_ptr<T> get(int idx)
    {
      return data[idx];
    }
    void add(shared_ptr<T> value)
    {
      data.push_back(value);
    }
};

Это обеспечивает корректность Const. Как вы видите, метод ADD () не использует , но потому что вы собираетесь хранить класс для хранения TS не const Ts. Но при доступе к нему Const вы возвращаете , который не проблема, поскольку shared_ptr может быть легко преобразован в shared_ptr . И SICE оба GET () методы возвращают копии Shared_PTR во внутреннем хранилище, вызывающий абонент не может случайно изменять объект ваших внутренних указателей. Это все сопоставимо с не умным указателем вариант:

template <typename T>
class MyExamplePtr
{
  private:
    vector<T *> data;

  public:
    const T *get(int idx) const
    {
      return data[idx];
    }
    T *get(int idx)
    {
      return data[idx];
    }
    void add(T *value)
    {
      data.push_back(value);
    }
};
12
ответ дан 26 November 2019 в 23:54
поделиться

Shared_PTR и Shared_PTR не взаимозаменяются . Это идет один путь - Shared_PTR преобразован в Shared_ptr , но не обратный.

Наблюдайте:

// f.cpp

#include <memory>

int main()
{
    using namespace std;

    shared_ptr<int> pint(new int(4)); // normal shared_ptr
    shared_ptr<const int> pcint = pint; // shared_ptr<const T> from shared_ptr<T>
    shared_ptr<int> pint2 = pcint; // error! comment out to compile
}

Компиляция через

CL / EHSC F.CPP

Вы также можете перегружать функцию на основе постоянной связи. Вы можете объединить, чтобы сделать эти два факта, чтобы сделать то, что вы хотите.

Что касается вашего второго вопроса, Myexample , вероятно, имеет больше смысла, чем Myexample .

37
ответ дан 26 November 2019 в 23:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: