Какой тип (авто) указателя использовать?

Я натолкнулся на несколько вопросов, где ответы утверждают, что использование 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++, вы передаете (по-английски) ссылку на внутреннее хранилище, которое изменится. Я думаю, что ваш стандарт кодирования пытается вам вообще не делать этого, не столько, что вы не можете использовать ссылки для этого, но что вы можете сделать это по-другому.

Другие вопросы по тегам