[C++] Smart pointer

aleks058

Заценил auto_ptr.
Он работает по принципу "кто последний - тот отец".
Ясно, что это фигово, если сделать, например, так:

auto_ptr<MyClass> GetMyClass
{
    auto_ptr<MyClass> p1new MyClass;
    auto_ptr<MyClass> p2 = p1;
    return p1;
}

Насколько я понимаю, от такого можно избавиться, если использовать smart pointer со счетчиком ссылок.
 
Вопрос. Есть ли где-нибудь уже реализованный?

Helga87

Дай угадаю. В boost есть.

bobby

Вот в boost он мне не понравился чем-то, только я забыл, чем =)

Helga87

Спасибо за ваш аргументированный комментарий

aleks058

Ща гляну в буст

Жаль, что в стандартной библиотеке нету ничего получше auto_ptr.

Мне вот интересно, какого auto_ptr без счетчика ссылок сделали. Можно было бы почти нахаляву намного более удобную штуку включить в стандартную библиотеку. Память экономили, штоле

aleks058

А где понравился?

bobby

Понравилась своя реализация, но она требует, чтобы объект, на который указывает smart pointer, наследовал некоторый маленький классик.

bobby

А я уже вспомнил. Он хранит счетчик ссылок отдельно от объекта, на который ссылаются смартпоинтеры, и при присвоениях смартпоинтеров копируются указатель на объект и указатель на счетчик. Это, вроде, хорошо, т.к. не накладывает никаких ограничений на классы указываемых объектов (в моей реализации они должны наследоваться от некоторого базового класса, в котором и содержится счетчик ссылок).
При этом возникает проблема в следующем коде:
MyClass * myObjectPtr = ...
smart_ptr<MyClass> ptr(myObjectPtr);
MyClass * myObjectPtr2 = ptr;
smart_ptr<MyClass> ptr2 = myObjectPtr2;

Т.е. при копировании смартпоинтеров не напрямую, а через промежуточный указатель. Разумеется, счетчиков ссылок становится при таком подходе две штуки, что совсем неправильно.
Но такое мне лично нужно было делать только 1 раз (вообще, вряд ли это считается хорошим тоном поэтому, наверное, это не очень часто встречающаяся проблема.

aleks058

Понятна.
Надо договориться с самим собой и пользоваться везде только smart поинтерами - тогда таких проблем не будет.
Ща буду договариваться

bobby

А, вот, я вспомнил, зачем мне потребовалось так делать.
Я писал паттерн visitor и везде использовал smart pointer'ы.
А вот один из методов acceptVisitor:
class Element1: public Element {
public:
void acceptVisitor(shared_ptr<Visitor> visitor) {
visitor->visitElement1(shared_ptr<Element1>(this;
}
}
Тут неизбежно произойдет появление нового счетчика ссылок, потому что, увы, this имеет тип Element1 *, а не shared_ptr<Element1>.

aleks058

Да. Пожалуй, без наследования с такими косяками не справиться.
Хорошо хоть множественное наследование в плюсах есть.

ЗЫ. Уже неделю, наверное, прогаю на плюсах - давно не приходилось. Такие забавные ощущения.
То думаю: "Бля, ну че за йобнутый языг", а иногда: "Какие же все-таки плюсы гибкие!".
Сейчас снова одолевает первая мысль.

erotic

Я не понял, что ты хочешь, чтобы делала твоя функция?

aleks058

Я хочу, чтобы несмотря на то, что я вернул "не тот" указатель, объект не удалился.
Минус auto_ptr в том, что при копировании меняется объект, который я копирую.
Я, например, люблю делать синонимы с коротким именем, которыми пользуюсь внутри блока кода. А тут получается, что мне этим синонимом придется пользоваться всегда.
Еще забавный эффект будет, если написать так:

auto_ptr<MyClass> pointerToMyClass(new MyClass;
{
auto_ptr<MyClass> p = pointerToMyClass; // Создал синоним
// Работаю с p
// ...

// Ща выйду из блока и мой объект сдохнет
}
// Оппа. pointerToMyClass уже давно указывает никуда

erotic

А можешь привести пример использования твоей функции?
Я понял твою проблему, но я не понял, как ты хочешь ее решить.
Функция GetMyClass, по-моему,делает следующее:
1. Создает экземпляр MyClass и засовывает указатель на него в p1.
2. Присваивает p2 = p1, p1 теперь указывает на ноль.
3. p2 уничтожается, т.е. уничтожается экземпляр MyClass.
4. Функция возвращает auto_ptr<MyClass>(0).
Вот все-таки зачем оно тебе надо?

Dasar

> Я, например, люблю делать синонимы с коротким именем
так почему не делаешь ссылки? они же для этого и созданы
хотя бы так:

auto_ptr<MyClass> pointerToMyClass(new MyClass;
{
auto_ptr<MyClass>& p = pointerToMyClass;
}

aleks058

Встречный вопрос: можешь привести пример использования программы Hello, World?
Это модельный пример, а не кусок кода из реальной жизни.
То, что после строчки
p2 = p1

p1 указывает никуда, само по себе нелогично. Зачем для auto_ptr так перегрузили оператор присваивания мне не понятно. Лучше бы запретили его вообще. Хотя в этом случае STL будет сосать.

В общем, пример с синонимом чем не подходит?

aleks058

Если я забуду поставить &, то компилятор мне ничего не скажет и ошибку я найду не очень скоро.
Плохо, когда приходится следить за мелочами.

erotic

Да не, пример подходит как нельзя лучше =)
В смысле, я понял, что тебе нужен класс со счетчиком ссылок для корректного удаления объекта при использовании синонимов.
Меня просто смутила странная функция в твоем первом посте
А вообще - прав на все 100, для синонимов используй &. Если ты будешь помнить про коварное свойство auto_ptr, то не будешь забывать его ставить

aleks058

Помнить буду, канешна, пока не забуду
Вот пример посложнее. Тут сцылками обойтись не получица.

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 тут: , так как этот подход позволяет работать с указателями наиболее однородно.

kokoc88

Программы на С++ лучше писать с как можно меньшим числом хранимых указателей. На самом деле, даже при использовании указателей с подсчётом ссылок, будут возникать проблемы. Почти все они описаны в статьях и книжках по COM. Существует набор правил для работы с подсчётом ссылок, но я уже забыл, как быстро отыскать это в MSDN'е.

aleks058

Надо сказать, что проблемы возникают только при межпроцессном взаимодействии. Это не мой случай
Проблемы в COM в том, что пользователь объекта должен явно сказать, что он его отпускает. То есть если прога упала так, что не вызвались деструкторы, объект зависает в памяти, так как он был вне памяти упавшего процесса.
В .Net с этим борются отказом от подсчета ссылок, заменяя его механизмом лизинга

bastii

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

kokoc88

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

COM объекты, работающие в другом процессе, будут корректно освобождены при падении программы.

aleks058

А, точно! Циклические ссылки! Совсем про них забыл.
Но что за проблемы с созданием переменных, возвращением значений и передачей параметров? Смарт пойнтеры с подсчетом ссылок с этими проблемами справляются нормально.
Оставить комментарий
Имя или ник:
Комментарий: