Могут ли умные указатели в Objective-C ++ полностью заменить AR C? - PullRequest
2 голосов
/ 05 апреля 2020

Я новичок в среде Какао и у меня вопрос:

Предположим, я не использую "голые" NS-указатели в своем приложении, тогда AR C для меня излишен? : -)

Другими словами, охватывает ли следующая реализация все проблемы AR C? : -)

Спасибо!

Сначала (накопление результатов "allo c ..", "new ..", "copy .." или "mutableCopy ..") :

#pragma once

// In-Ref(NOP), Out-Ref(--)
template<typename T>
class NSChargePtr
{
  NSChargePtr(const NSChargePtr&) = delete;

protected:
  T* m_object{};

public:
  NSChargePtr(T* p = __nullptr)
    : m_object(p)
  {
  }
  virtual ~NSChargePtr()
  {
    [m_object release];
  }
  operator T*()
  {
    return m_object;
  }
  operator bool()
  {
    return __nullptr != m_object;
  }
  void operator=(T* p)
  {
    reset(p);
  }
  T* get()
  {
    return m_object;
  }
  virtual void reset(T* p = __nullptr)
  {
    [m_object release];
    m_object = p;
  }
}; 

... и второй (локальное хранение, перевод):

#pragma once
#include "NSChargePtr.h"

// In-Ref(++), Out-Ref(--)
template<typename T>
class NSPassPtr : public NSChargePtr<T>
{
public:
  NSPassPtr(T* p = __nullptr)
    : NSChargePtr<T>(p)
  {
    [NSChargePtr<T>::m_object retain];
  }
  NSPassPtr(const NSPassPtr& other)
    : NSChargePtr<T>(other.m_object)
  {
  }
  virtual void reset(T* p = __nullptr) override
  {
    NSChargePtr<T>::reset(p);
    [NSChargePtr<T>::m_object retain];
  }
  void operator=(T* p)
  {
    NSChargePtr<T>::operator=(p);
  }
};

1 Ответ

1 голос
/ 06 апреля 2020

Короче говоря: Вы можете сделать это, но это, вероятно, не будет таким же безболезненным, как "настоящий" AR C, и не ясно, что этот подход обеспечивает какое-либо улучшение более AR C. Почему вы даже хотите это сделать?

Некоторые потенциальные проблемы, которые сразу бросаются в глаза:

  • Ваше различие между NSPassPtr и NSChargePtr уже является основным источником потенциальная путаница. Вы должны точно знать, какой из них использовать в каком случае, в зависимости от того, возвращает ли метод автоматически выпущенное значение или оставшееся значение. Вы также не можете точно переназначить результат выражения автоматического высвобождения переменной, которая была инициализирована с результатом сохраняющего выражения.
{
   NSChargePtr<MyClass> obj = [[MyClass alloc] init];
   // …
   obj = [foo bar];
   // …
} // over-release of result of [foo bar];
  • Безопасность потока. Я не вижу никаких доказательств защиты от условий гонки в вашей реализации. AR C имеет четко определенное поведение в контексте многопоточности.
  • Производительность и оптимизация компилятора. Компилятор знает об AR C и может разрешить сохранять и освобождать вызовы, если он может доказать, что они не нужны. Это не может сделать это с этой реализацией. AR C objc_retain / objc_release, вероятно, быстрее, чем отправка retain / release сообщений.
  • Неявные перегрузки оператора преобразования (operator T*(), operator bool, не- explicit конструкторы, такие как NSChargePtr(T* p = __nullptr)), как правило, являются источником ошибок.

Следует отметить, что Objective-C ++ совместим с AR C и что AR C ссылки ведут себя хорошо в контексте конструирования / уничтожения объектов C ++. Поэтому, как правило, если вы действительно пытаетесь заставить какой-то фрагмент кода работать с AR C, лучше перенести его в отдельный файл кода с отключенным AR C, но оставить AR C включенным для остальных проекта.

Наконец:

NSPassPtr(const NSPassPtr& other)
    : NSChargePtr<T>(other.m_object)
  {
  }

Мне кажется, что в нем отсутствует retain?

...