Код, с которым я работаю, имеет свою собственную реализацию интеллектуального указателя, которая делает простой подсчет ссылок. Да, у нас не должно быть собственной реализации. Да, мы должны использовать один из 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 ужасно, когда я только предоставил шаблонную версию конструктора копий, заменив оригинальную не-шаблонную версию. В конце концов, я понял, что компилятор не рассматривает шаблонную версию как конструктор копирования и предоставляет по умолчанию. Значение по умолчанию просто тупо копирует содержимое без обновления счетчика, поэтому я заканчиваю болтающимися указателями и двойными разрядами. То же самое относится к оператору присваивания.
Трудно предотвратить доступ к необработанному указателю. & * CounterPointer() обычно является сырым T *. Однако не работает с нулевыми указателями. –
MSalters
Я чувствую, что предоставление функции как части интерфейса предполагает, что использование необработанного указателя - хорошая идея. Если кто-то решит, что им нужно получить исходный указатель, они все равно изменят интерфейс. Это довольно мало; если бы это был мой код, это меня не сильно беспокоило. – Ned