Какой тип (авто) указателя использовать?
Я натолкнулся на несколько вопросов, где ответы утверждают, что использование T* никогда не является лучшей идеей.
Хотя я уже много использую RIIC, в моем коде есть одна особенность, где я использую T*. Читая о нескольких авто-указателях, я не смог найти ни одного, где бы я сказал, что у меня есть явное преимущество от его использования.
Мой сценарий:
class MyClass
{
...
// This map is huge and only used by MyClass and
// and several objects that are only used by MyClass as well.
HashMap<string, Id> _hugeIdMap;
...
void doSomething()
{
MyMapper mapper;
// Here is what I pass. The reason I can't pass a const-ref is
// that the mapper may possibly assign new IDs for keys not yet in the map.
mapper.setIdMap(&_hugeIdMap);
mapper.map(...);
}
}
MyMapper
теперь имеет HashMap<...>*
член, который - согласно высоко голосуемым ответам в вопросах о не связанных проблемах - никогда не является хорошей идеей (хотя картограф будет выходить за рамки, прежде чем MyClass
и, следовательно, я не считаю это слишком большой проблемой. Нет никаких new
в маппере и нет delete
будут необходимы).
Так что же является лучшей альтернативой в этом конкретном случае использования?
3 ответа
Лично я думаю, что необработанный указатель (или ссылка) здесь хорошо. Умные указатели связаны с управлением временем жизни указанного объекта, и в этом случае MyMapper
не управляет временем жизни этого объекта, MyClass
является. У вас также не должно быть умного указателя, указывающего на объект, который не был динамически выделен (чего в данном случае нет в хэш-карте).
Лично я бы использовал что-то вроде следующего:
class MyMapper
{
public:
MyMapper(HashMap<string, Id> &map)
: _map(map)
{
}
private:
HashMap<string, Id> &_map
};
Обратите внимание, что это предотвратит MyMapper
от наличия оператора присваивания, и он может работать, только если допустимо передать HashMap в конструктор; если это проблема, я бы сделал член указателем (хотя я все равно передал бы аргумент в качестве ссылки и сделал бы _map(&map)
в списке инициализатора).
Если это возможно для MyMapper
или любой другой класс, использующий хэш-карту для выживания MyClass
тогда вы должны начать думать об умных указателях. В этом случае, я бы порекомендовал std::shared_ptr
, но вы должны будете использовать его везде: _hugeIdMap
должен был быть shared_ptr
к динамически распределенному значению, а не к обычному полю без указателя.
Обновить:
Поскольку вы сказали, что использование ссылки недопустимо из-за стандартов кодирования проекта, я бы предложил просто придерживаться необработанного указателя по причинам, указанным выше.
Голые указатели (обычно называемые необработанными указателями) хороши, когда объект не несет ответственности за удаление объекта. В случае с MyMapper указатель указывает на объект, уже принадлежащий MyClass, и поэтому абсолютно нормально не удалять его. Проблема возникает, когда вы используете необработанные указатели, когда вы намерены удалить объекты через них, в этом и заключаются проблемы. Люди задают вопросы только тогда, когда у них есть проблемы, поэтому вы почти всегда видите, что они используются только в проблемном контексте, но необработанные указатели в несобственном контексте - это хорошо.
Как насчет передачи его в конструктор и сохранения ссылки (или const-ссылки) на него? Таким образом, ваше намерение не владеть объектом становится ясным.
Проходные авто-указатели или общие-указатели в основном предназначены для передачи информации о владельце.
- общие указатели указывают, что это общий
- автоматические указатели указывают на то, что это ответственность получателей
- ссылки указывают, что это ответственность отправителей
- пустые указатели ничего не указывают.
О вашем стиле кодирования:
наши стандарты кодирования имеют соглашение, которое гласит: никогда не передавайте неконстантные ссылки.
Используете ли вы механизм ссылок C++ или механизм указателей C++, вы передаете (по-английски) ссылку на внутреннее хранилище, которое изменится. Я думаю, что ваш стандарт кодирования пытается вам вообще не делать этого, не столько, что вы не можете использовать ссылки для этого, но что вы можете сделать это по-другому.