2009-02-18 3 views
3

Код, с которым я работаю, имеет свою собственную реализацию интеллектуального указателя, которая делает простой подсчет ссылок. Да, у нас не должно быть собственной реализации. Да, мы должны использовать один из boost или некоторые из них. Потерпите меня.Проблемы с написанием конструктора копий для умного указателя

я обнаружил, что хотел написать такой код:

... 
CountedPointer<Base> base; 
... 
CountedPointer<Derived> derived; 
... 
base = derived; 

Однако конструктор копирования для CountedPointer имеет прототип, как это:

CountedPointer(const CountedPointer<T> &other); 

Так приведенный выше код не будет компилироваться, так как он не может найти подходящий конструктор (или оператор присваивания - это та же история). Я попытался переписывания конструктор копирования с прототипом, как это:

template<U> 
CountedPointer(const CountedPointer<U> &other); 

Однако, я попал в проблему, конструктор копирования должен получить доступ к закрытому члену объекта это копирование (т.е. сырой указатель), и если это в другой специализации CountedPointer, они не видны.

Alexandrescu избегает этой проблемы в своей библиотеке Loki, имея функции доступа для инкапсулированного указателя, но я бы предпочел не давать прямой доступ к необработанному указателю, если это возможно.

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

Обновление: Я реализовал принятый ответ ниже, и он работает хорошо. Я потратил некоторое время на то, чтобы выяснить, почему моя программа seg-faulted ужасно, когда я только предоставил шаблонную версию конструктора копий, заменив оригинальную не-шаблонную версию. В конце концов, я понял, что компилятор не рассматривает шаблонную версию как конструктор копирования и предоставляет по умолчанию. Значение по умолчанию просто тупо копирует содержимое без обновления счетчика, поэтому я заканчиваю болтающимися указателями и двойными разрядами. То же самое относится к оператору присваивания.

+0

Трудно предотвратить доступ к необработанному указателю. & * CounterPointer () обычно является сырым T *. Однако не работает с нулевыми указателями. – MSalters

+0

Я чувствую, что предоставление функции как части интерфейса предполагает, что использование необработанного указателя - хорошая идея. Если кто-то решит, что им нужно получить исходный указатель, они все равно изменят интерфейс. Это довольно мало; если бы это был мой код, это меня не сильно беспокоило. – Ned

ответ

4

Разве вы не можете сделать их друзьями? Как:

template<typename T> 
class CountedPointer { 

    // ... 

    template<U> 
    CountedPointer(const CountedPointer<U> &other); 

    template<typename U> friend class CountedPointer; 
}; 
+0

Это делает трюк! Интересно, можете ли вы добавить некоторые подробности о том, что здесь происходит? Например, я не совсем уверен, почему шаблон объявления приглашен. – Ned

+0

Я не уверен, как объявление шаблона U в друге связано с U в объявлении шаблона конструктора копирования –

+0

@Doug T. U в другом не имеет отношения к U в копии ctor. Я мог бы использовать V для друга, и он будет работать так же. – mitchnull

3

«Alexandrescu устраняет эту проблему в своей библиотеке Loki, имея функции доступа для инкапсулированных указатель, но я бы предпочел не давать прямой доступ к необработанным указатель, если это возможно»

Я думаю, что стоимость добавления raw pointer getter будет намного меньше, чем сложность, связанная с попыткой обойтись без наличия необработанного доступа. Просто не существует языкового механизма для преобразования экземпляров между двумя несвязанными классами шаблонов. Для компилятора они представляют собой две совершенно разные вещи без отношения во время выполнения. Вот почему один экземпляр класса шаблона не может получить доступ к другим частным лицам.

Вы можете подумать о создании таких отношений с базовым классом для всех счетчиков. Возможно, вам придется поместить void * в этот базовый класс. Тогда вам нужно будет все проверить самостоятельно (это Terred from U, затем принудительное действие ... Могу ли я неявно преобразовать T в U ?, если так заставить конвертировать .. и т. Д.), Но это может стать довольно сложным , Вот приблизительный старт для этого подхода:

class CountedPointerBase 
{ 
    void* rawPtr; 
}; 

template <class T> 
class CountedPointer : public ConutedPointerBase 
{ 
     T* myRawT = reinterpret_cast<T*>(rawPtr); 

     template<class U> 
     CountedPointer(CountedPointer<U> u) 
     { 
      // Copying a CountedPointer<T> -> CountedPointer<U> 
      if (dynamic_cast<U*>(myRawT) != NULL) 
      { 
       // Safe to copy one rawPtr to another 
      } 
      // check for all other conversions 
     } 
} 

Возможно, существует много других сложностей в отношении того, совместимы ли два типа. Может быть, есть некоторые шаблоны шаблонов Loki/Boost, которые могут определять для двух аргументов типа, если вы можете отбрасывать один в другой.

В любом случае, как вы можете видеть, это может быть гораздо более сложное решение, а затем просто добавить геттер.Возможность получить исходный указатель имеет и другие преимущества. Вы можете передать исходные указатели в функции библиотеки, которые принимают только исходные указатели и используют их как временные, например. Возможно, это опасно, если кто-то из вашей команды решит удержать копию необработанного указателя, а не умного ptr. Вероятно, этот человек должен быть кратковременным.

0

Вы решить эту проблему, если у вас есть CountedPointer (T * прочее); конструктор и аналогичный оператор присваивания.

+0

Не означает ли это, что CountedPointer неявно конвертируется в T *? В этом суть его проблемы, они действительно не ... –

+0

Yeap, это подразумевается. Я не вижу проблемы с объявлением оператора T *, чем вернет завернутый указатель. – sharptooth

+0

Я бы не дал никому доступ к необработанному указателю. Что делать, если они удаляют его? Или держать его вне времени жизни CounterPointer? Разрешение неявного преобразования также позволяет «удалить cp;» для компиляции для CountedPointer cp - и он оставит свисающий указатель в cp. – Ned

Смежные вопросы