[C++] Smart pointer
Дай угадаю. В boost есть.
Вот в boost он мне не понравился чем-то, только я забыл, чем =)
![](/images/graemlins/smile.gif)
![](/images/graemlins/smile.gif)
Жаль, что в стандартной библиотеке нету ничего получше auto_ptr.
Мне вот интересно, какого auto_ptr без счетчика ссылок сделали. Можно было бы почти нахаляву намного более удобную штуку включить в стандартную библиотеку. Память экономили, штоле
![](/images/icons/confused.gif)
А где понравился?
Понравилась своя реализация, но она требует, чтобы объект, на который указывает smart pointer, наследовал некоторый маленький классик.
При этом возникает проблема в следующем коде:
MyClass * myObjectPtr = ...
smart_ptr<MyClass> ptr(myObjectPtr);
MyClass * myObjectPtr2 = ptr;
smart_ptr<MyClass> ptr2 = myObjectPtr2;
Т.е. при копировании смартпоинтеров не напрямую, а через промежуточный указатель. Разумеется, счетчиков ссылок становится при таком подходе две штуки, что совсем неправильно.
Но такое мне лично нужно было делать только 1 раз (вообще, вряд ли это считается хорошим тоном
![](/images/graemlins/laugh.gif)
Надо договориться с самим собой и пользоваться везде только smart поинтерами - тогда таких проблем не будет.
Ща буду договариваться
![](/images/icons/laugh.gif)
Я писал паттерн visitor и везде использовал smart pointer'ы.
А вот один из методов acceptVisitor:
class Element1: public Element {Тут неизбежно произойдет появление нового счетчика ссылок, потому что, увы, this имеет тип Element1 *, а не shared_ptr<Element1>.
public:
void acceptVisitor(shared_ptr<Visitor> visitor) {
visitor->visitElement1(shared_ptr<Element1>(this;
}
}
Хорошо хоть множественное наследование в плюсах есть.
ЗЫ. Уже неделю, наверное, прогаю на плюсах - давно не приходилось. Такие забавные ощущения.
То думаю: "Бля, ну че за йобнутый языг", а иногда: "Какие же все-таки плюсы гибкие!".
Сейчас снова одолевает первая мысль.
Я не понял, что ты хочешь, чтобы делала твоя функция?
Минус auto_ptr в том, что при копировании меняется объект, который я копирую.
Я, например, люблю делать синонимы с коротким именем, которыми пользуюсь внутри блока кода. А тут получается, что мне этим синонимом придется пользоваться всегда.
Еще забавный эффект будет, если написать так:
auto_ptr<MyClass> pointerToMyClass(new MyClass;
{
auto_ptr<MyClass> p = pointerToMyClass; // Создал синоним
// Работаю с p
// ...
// Ща выйду из блока и мой объект сдохнет
}
// Оппа. pointerToMyClass уже давно указывает никуда
Я понял твою проблему, но я не понял, как ты хочешь ее решить.
Функция GetMyClass, по-моему,делает следующее:
1. Создает экземпляр MyClass и засовывает указатель на него в p1.
2. Присваивает p2 = p1, p1 теперь указывает на ноль.
3. p2 уничтожается, т.е. уничтожается экземпляр MyClass.
4. Функция возвращает auto_ptr<MyClass>(0).
Вот все-таки зачем оно тебе надо?
так почему не делаешь ссылки? они же для этого и созданы
хотя бы так:
auto_ptr<MyClass> pointerToMyClass(new MyClass;
{
auto_ptr<MyClass>& p = pointerToMyClass;
}
Это модельный пример, а не кусок кода из реальной жизни.
То, что после строчки
p2 = p1
p1 указывает никуда, само по себе нелогично. Зачем для auto_ptr так перегрузили оператор присваивания мне не понятно. Лучше бы запретили его вообще. Хотя в этом случае STL будет сосать.
В общем, пример с синонимом чем не подходит?
Плохо, когда приходится следить за мелочами.
В смысле, я понял, что тебе нужен класс со счетчиком ссылок для корректного удаления объекта при использовании синонимов.
Меня просто смутила странная функция в твоем первом посте
![](/images/graemlins/smile.gif)
А вообще - прав на все 100, для синонимов используй &. Если ты будешь помнить про коварное свойство auto_ptr, то не будешь забывать его ставить
![](/images/graemlins/smile.gif)
![](/images/graemlins/smile.gif)
Вот пример посложнее. Тут сцылками обойтись не получица.
class A
{
};
class B
{
private:
auto_ptr<A> a;
public:
SetA(auto_ptr<A> a)
{
this->a = a;
}
};
void main(void)
{
auto_ptr<A> a;
{
B b;
b.SetA(a);
}
// Тут a уже помер, потому что b помер
}
в общем,
либо приходится где-то пользоваться указателями, где-то ссылками на умный указатель, а где-то просто умными указателями, причем внимательно за всей этой фигней следить,
либо пользоваться умным указателем со счетчиком ссылок, причем по возможности таким, какой описал Madkroz тут: , так как этот подход позволяет работать с указателями наиболее однородно.
Программы на С++ лучше писать с как можно меньшим числом хранимых указателей. На самом деле, даже при использовании указателей с подсчётом ссылок, будут возникать проблемы. Почти все они описаны в статьях и книжках по COM. Существует набор правил для работы с подсчётом ссылок, но я уже забыл, как быстро отыскать это в MSDN'е.
![](/images/graemlins/wink.gif)
Проблемы в COM в том, что пользователь объекта должен явно сказать, что он его отпускает. То есть если прога упала так, что не вызвались деструкторы, объект зависает в памяти, так как он был вне памяти упавшего процесса.
В .Net с этим борются отказом от подсчета ссылок, заменяя его механизмом лизинга
![](/images/icons/blush.gif)
Причем здесь процессы. Там основная проблема с цикличными ссылками, когда нужно отслеживать схему взаимодействия объектов, и порядок, в котором их отписывать/отсоединять и удалять.
COM объекты, работающие в другом процессе, будут корректно освобождены при падении программы.
Но что за проблемы с созданием переменных, возвращением значений и передачей параметров? Смарт пойнтеры с подсчетом ссылок с этими проблемами справляются нормально.
Оставить комментарий
aleks058
Заценил auto_ptr.Он работает по принципу "кто последний - тот отец".
Ясно, что это фигово, если сделать, например, так:
Насколько я понимаю, от такого можно избавиться, если использовать smart pointer со счетчиком ссылок.
Вопрос. Есть ли где-нибудь уже реализованный?