потокобезопасный оператор присваивания копии для класса интеллектуальных указателей

Я реализую класс интеллектуального указателя, и у меня возникло несколько недоразумений. Был бы очень признателен, если бы люди могли помочь мне уточнить.

1: я думал, что в классе умного указателя должно быть «new» в конструкторе, «delete» в desctructor. Но я не могу найти место для «нового» … Значит, пользователь будет отвечать за создание нового, а класс интеллектуальных указателей поможет его очистить?

2: При разработке оператора присваивания копии популярным подходом было копирование-n-swap, чтобы быть потокобезопасным. Однако copy-n-swap требует, чтобы объект передавался по значению (а не по ссылке). Можно ли его использовать при разработке умного указателя? Меня беспокоило то, что это класс указателя, поэтому он не может передавать значение. Но я не очень уверен в этом.

3: если меня попросят кодировать умный указатель на собеседовании, должен ли я предоставить какой-либо тип подсчета ссылок? Количество ссылок на мысли зависит от shared_ptr …

4: Это, должно быть, глупый вопрос, но лучше спросите, а затем сохраните сомнения внутри. за SmartPointer<T>& sp для доступа к ptr, если он использует sp->ptr или же sp.ptr??

Ценю ваш вклад.

template <class T>
class SmartPointer{
T* ptr;
public:
SmartPointer():ptr(NULL){}
SmartPointer(const T& p):ptr(p){}
SmartPointer(const SmartPointer<T>& sp):ptr(sp->ptr){}
SmartPointer<T>& operator=(const SmartPointer<T>& sp);
~SmartPointer(){delete ptr;}
T& operator*(){return *ptr;}
T* operator->(){return ptr;}
};

SmartPointer& operator=(const SmartPointer& sp){
T* pOrig = ptr;
ptr = new T(sp.ptr);
delete pOrig;
return *this;
}

2

Решение

Таким образом, пользователь будет отвечать за создание нового, а умный указатель
класс помогает навести порядок?

Да, обычно это то, что делается. Пример:

std::unique_ptr<Foo> smart_ptr(new Foo);

Одна из причин, почему конструирование (и распределение) оставлено на усмотрение клиента, заключается в том, что T может иметь все виды параметризованных конструкторов. Было бы сложно, если не сказать больше, и, вероятно, задействовать шаблоны конструкторов с переменным квадратом с действительно причудливой магией шаблонов, если вы хотите, чтобы умный указатель создавал T сам по себе со всеми возможностями. Проще просто позволить клиенту передать указатель при создании умного указателя. Пока они делают это прямо на строительстве, это безопасно, так как если operator new бросает, прежде чем мы доберемся до конструкции интеллектуального указателя, ничего не будет выделено / построено, и поэтому не будет ничего для очистки, кроме того, что уже находится в стеке вызовов (что должно соответствовать RAII для безопасности исключений).

Если вы хотите сделать его устойчивым к границам API, то обычно вам нужно захватить «средство удаления», которое будет вызывать «оператор удаления» на том же сайте, на котором был сгенерирован код (важно при работе через границы модуля, когда пытаются освободить память в модуле B память, выделенная в модуле A, может привести к неопределенному поведению).

Однако copy-n-swap требует, чтобы объект передавался по значению (а не по
ссылка). Можно ли его использовать при разработке умного указателя? мой
обеспокоенность заключалась в том, что это класс указателя, следовательно, может быть не в состоянии
передать по значению. Но я не очень уверен в этом.

Для такого рода интеллектуального указателя, который вы делаете, который не использует подсчет ссылок, обычно лучше всего запрещать копирование (как присваивание, так и копирование ctor, хотя ctor с перемещением в порядке).

В противном случае вы возвращаетесь к архаичной практике передачи прав собственности (как в случае с древними std::auto_ptr) или пытаясь глубоко скопировать pointee.

Передача права собственности может быть особенно подвержена человеческим ошибкам, поскольку она рассматривает источник, из которого копирует, как изменчивый (что является совершенно необычным и триповым поведением). Если вы сделаете это, вы можете использовать атомарный CAS для замены указателей, но вам нужно заставить конструктор копирования и оператор присваивания принимать вещи по ссылке, а не по константной ссылке или по значению, поскольку он будет обрабатывать источник как изменяемый ( или сделать частный ptr член у вас изменчивый и используйте константную ссылку).

Глубокое копирование pointee является довольно интересной идеей, но одна из проблем заключается в том, что кто-то может попытаться скопировать ваш умный указатель на сайт, где T не является полным типом (не определено, только объявлено). Это похоже на проблему с деструкторами, поэтому, если вы хотите сделать интеллектуальный указатель глубокого копирования, как этот, надежным решением будет захватить конструктор копирования T (например: сохранить указатель функции на функцию, которую вы генерируете, когда ваш интеллектуальный указатель) построен, чтобы клонировать / скопировать построить новые элементы T).

Также небольшое исправление для существующего кода глубокого копирования:

SmartPointer& operator=(const SmartPointer& sp){
T* pOrig = ptr;
ptr = new T(*sp.ptr); <-- need to dereference here
delete pOrig;
return *this;
}

3: Это, должно быть, глупый вопрос, но лучше спросите, а затем продолжайте сомневаться
внутри. для SmartPointer& sp для доступа к ptr, если он использует sp-> ptr или
sp.ptr ??

Пусть компилятор исправит ваши сомнения. Учитывая ссылку, SmartPointer& sp, sp->ptr будет ошибка компилятора в этом случае, если T имеет члена под названием ptr Вы можете получить доступ, что, вероятно, не то, что вы хотите в любом случае. sp->ptr назвал бы ваш перегруженный operator->, не получить доступ к фактическому закрытому члену интеллектуального указателя. operator-> обычно определяется только для указателей, поэтому попытка использовать его в качестве ссылки или константной ссылки вызовет ваши перегруженные, определенные пользователем операторы.

1

Другие решения

1: я сказал бы, что конструктор — это такое место:

SmartPointer(T* p):ptr(p){}

затем вы получаете тот же синтаксис, что и в типичном умном указателе — вы создаете его, вызывая SmartPointer objPtr(new Obj()); , Пользователь может создать свой объект так, как он хочет, и умный указатель отвечает за его очистку (поскольку это главная проблема, с которой умные указатели были разработаны, чтобы помочь). Обратите внимание, что в будущем вы можете добавить std::make_shared() метод, позволяющий избежать копирования вашей оболочки при создании и повышении производительности.


2: Вы должны думать о том, как поведет себя ваш умный указатель. Помните, что когда вы пытаетесь скопировать необработанный указатель, вы копируете только адрес, а не сам объект. Таким образом, если вы решите обращаться с SmartPointer как с обычным указателем, оснащенным сборщиком мусора, тогда вы можете свободно реализовывать функцию copy-n-swap. С другой стороны, вы можете удалить Оператор = () как в std::unique_ptr или попробуйте реализовать подсчет ссылок как в std::shared_ptr,


3: я сказал бы, только если Вас просят сделать это явно. Обычно умный указатель Можно понять какую-то оболочку, которая сама по себе может контролировать время жизни необработанного указателя. Хотя, я уверен, что если они спросят «пожалуйста, напишите реализацию простого умного указателя», а вы спросите «хотите ли вы, чтобы оно также обрабатывало совместное владение?», Вы получите точку 🙂


4: sp.ptr конечно 🙂 SmartPointer<T>& sp является ссылкой, поэтому для доступа к его члену вы должны использовать точку . оператор.

Использовать sp->ptr вам бы пришлось иметь SmartPointer<T>* sp параметр.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector