У меня есть несколько контейнеров в классе, например, векторе или карте, которые содержат 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>
в класс сделайте меня:
shared_ptr<T>
или shared_ptr<const T>
в контейнере? shared_ptr<const T>
obj)? 2) Лучше инстанцировать классов следующим образом: MyExample<const int>
? Это кажется незаконно строгим, потому что я никогда не могу возвращать a shared_ptr<int>
?
Если кто-то передаст вам 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
)
Вы правы во втором утверждении, скорее всего, Вы не хотите инстанцировать Ваш класс как
, так как никогда не сможете модифицировать ни один из Ваших T
.
Одно можно понять, что:
Tr1 :: Shared_ptr
имитирует функциональность t const *
, а именно то, что он указывает на Const, но сам указатель нет.
Итак, вы можете назначить новое значение вашему общему указателю, но я ожидаю, что вы не сможете использовать ReareFerection Shared_PTR
в качестве L-значение.
Я бы предложил бы следующую мемотологию:
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 () не использует
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);
}
};
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
.