Swamp Board
система конференций сети SWAMP
 



 
 Новости  FAQ  Поиск  Закладки  Пользователи  Группы   Профиль  Войти и проверить личные сообщения  Вход 

RSS
» Добро пожаловать!
Сообщения без ответов
Корень форума > C++ > boost::shared_ptr
Предыдущая тема :: Следующая тема  
Нaчaть нoвую тeму   Отвeтить нa тeму
Распечатать тему
Flipp



  Цитировать Профиль  Сообщение    

Привет всем!
Собственно, есть примерно такой код
Код:
#include <boost> // тут, конечно же boost/shared_ptr.hpp, просто парсер съедает
#include <map>
#include <iostream>

class A;
typedef boost::shared_ptr<A> APtr;

class A
{
public:
A()
{
_myMMap.insert(std::pair<char>('a', APtr(this)));
}

void add(char ch, APtr a)
{
_myMMap.insert(std::pair<char>(ch, a));
}

protected:
std::multimap<char> _myMMap;
};

int main()
{
// пусть ptr1Count — количество ссылок на первый объект
// пусть ptr2Count — количество ссылок на второй объект
APtr ptr1(new A); // ptr1Count = 1 + 1, так как еще один указатель содается в мультимапе
APtr ptr2(new A); // ptr2Count = 1 + 1, так как еще один указатель содается в мультимапе
ptr1->add('b', ptr2); // ptr2Count++
ptr1->add('a', ptr1); // ptr1Count++
ptr2->add('c', ptr1); // ptr1Count++
int ptr1Count, ptr2Count;
ptr1Count = ptr1.use_count(); // по идее ptr1Count = 4
ptr2Count = ptr2.use_count(); // по идее ptr2Count = 3
std::cout << ptr1Count << '\n' << ptr2Count << std::endl;
return 0;
}

Но на выходе получаем значения 3 и 2 (даже если сделать конструктор пустым). Видимо, я чего-то не понимаю. Разъясните, пожалуйста. Да и вообще можно ли в таком случае пользоваться shared_ptr?

» Добавлено: Пн Сен 26, 2011 4:59 pm
Flipp



  Цитировать Профиль  Сообщение    

Прочитал, что анонимные экземпляры shared_ptr лучше не использовать, но там причина несколько иная. Ну и исправление этого косячка в конструкторе ничего не изменила.

» Добавлено: Пн Сен 26, 2011 5:11 pm
Spy



  Цитировать Профиль  Сообщение    

Хз как у тебя в комментах "по идее", но у меня получился реф каунтер 3 и 2 просто глядя на код. Ты погляди сколько и чего ты инсертишь в мэп, а сколько и чего на деле туда добавится. ;)

» Добавлено: Пн Сен 26, 2011 5:26 pm
Flipp



  Цитировать Профиль  Сообщение    

Spy, а эта строка конструктора класса А
Код:
_myMMap.insert(std::pair<char>('a', APtr(this)));
разве не приведет к инкременту счетчика?

» Добавлено: Пн Сен 26, 2011 5:54 pm
добрый пирожокs

avatar

  Цитировать Профиль  Сообщение    

Flipp, счетчик инкрементится только если `shared_ptr` создается из `shared_ptr`. У тебя же в конструкторе `A` вызывается `shared_ptr(A*)`. В строчке `APtr ptr1(new A)` также вызывается `shared_ptr(A*)`. По сути ты дважды создаешь shared_ptr на один и тот же объект, что в конечном счете может привести к двойному delete. А счетчик инкрементится у тебя только в строчках:
ptr1->add('b', ptr2); // ptr2Count++
ptr1->add('a', ptr1); // ptr1Count++
ptr2->add('c', ptr1); // ptr1Count++

_________________
Когда работники зоопарка били крокодила, я увидел крокодиловы слезы.

» Добавлено: Пн Сен 26, 2011 6:45 pm
добрый пирожокs

avatar

  Цитировать Профиль  Сообщение    

То, что ты хочешь сделать, можно реализовать при помощи boost::enable_shared_from_this
_________________
Когда работники зоопарка били крокодила, я увидел крокодиловы слезы.

» Добавлено: Пн Сен 26, 2011 6:50 pm
Flipp



  Цитировать Профиль  Сообщение    

добрый пирожок (Backslash), спасибо за разъяснение. Только меня смущает вот это требование:
Цитата:
Requires: enable_shared_from_this<T> ... *this must be a subobject of an instance t of type T . There must exist at least one shared_ptr instance p that owns t.

То есть один shared_ptr уже должен владеть данным объектом? Или я опять ошибаюсь?

» Добавлено: Пн Сен 26, 2011 8:30 pm
добрый пирожокs

avatar

  Цитировать Профиль  Сообщение    

Flipp, хз, ни разу не пользовался enable_shared_from_this =) попробуй, че
Насколько я понял тебе надо написать что-то вроде такого:
Код:

class A;
typedef boost::shared_ptr<A> APtr;

class A : public boost::enable_shared_from_this<A>
{
public:
  A()
  {
    _myMMap.insert(std::pair<char>('a', APtr(this)));
  }
....
};

int main()
{
  APtr ptr1((new A)->shared_from_this());
  ....
}


А еще лучше вот так:

Код:

class A : public boost::enable_shared_from_this<A>
{
private:
  A()
  {
    _myMMap.insert(std::pair<char>('a', APtr(this)));
  }
public:
  static shared_ptr<A> Create()
  {
     A *pThis = new A;
     return pThis->shared_from_this();
  }
....
};

int main()
{
  APtr ptr1 = A::Create();
  ....
}


Но ты ведь понимаешь, что это все ведет к утечке памяти (понимаешь ведь?), т.к. такие объекты никогда не будут удалены. По идее надо еще добавить что типа такого:
Код:

void A::Release()
{
  std::multimap<char> mymap;
  mymap.swap(_myMMap);
}


И в конце main добавить `ptr1->Release();` Но все равно код не перестает быть бредовым.

_________________
Когда работники зоопарка били крокодила, я увидел крокодиловы слезы.


Последний раз редактировалось: добрый пирожок (Пн Сен 26, 2011 9:47 pm), всего редактировалось 2 раз(а)

» Добавлено: Пн Сен 26, 2011 9:26 pm
Flipp



  Цитировать Профиль  Сообщение    

добрый пирожок (Backslash), ну, я все по мануалу сделал, унаследовал A от enable_shared_from_this, в конструкторе A написал бредовое
Код:
APtr a(shared_from_this());
вместо
Код:
APtr a(this)
и получил эксепшн. Думаю, может лучше будет воспользоваться weak_ptr...


Последний раз редактировалось: Flipp (Пн Сен 26, 2011 9:50 pm), всего редактировалось 1 раз

» Добавлено: Пн Сен 26, 2011 9:38 pm
добрый пирожокs

avatar

  Цитировать Профиль  Сообщение    

см. мое сообщение выше, я зааптейтил его =)
_________________
Когда работники зоопарка били крокодила, я увидел крокодиловы слезы.

» Добавлено: Пн Сен 26, 2011 9:41 pm
Flipp



  Цитировать Профиль  Сообщение    

Backslash:

см. мое сообщение выше, я зааптейтил его =)

Я прямо обновлять страницу не успеваю *Wink*
В общем-то действительно бредово получается. мне сейчас думается, что глупо было в мап пихать shared_ptr. Наверно достаточно будет слабых указателей, которые не владеют объектом...

» Добавлено: Пн Сен 26, 2011 9:48 pm
Spy



  Цитировать Профиль  Сообщение    

Flipp, а ты что вообще пытаешься этим кодом сделать? Понять как работают shared и weak ptr'ы?

» Добавлено: Пн Сен 26, 2011 9:53 pm
Flipp



  Цитировать Профиль  Сообщение    

Spy, и это тоже само-собой (впервые их использую). А вообще есть некое подобие графа, который содержит массив из указателей на объект класса вершины(для хранения и навигации по всем существующим объектам), при этом каждая вершина хранит в себе ассоциативный массив <ключ>, чтобы знать в какую вершину и при каком ключе можно попасть.

» Добавлено: Пн Сен 26, 2011 10:05 pm
2HeLLs



  Цитировать Профиль  Сообщение    

да shared_from_this нельзя вызывать из конструктора (как-то натыкался на это тоже), спасает создание инициализируещей функции, которую приходятся вызывать сразу после создания экземпляров класса

» Добавлено: Чт Сен 29, 2011 11:01 pm
добрый пирожокs

avatar

  Цитировать Профиль  Сообщение    

2HeLL (Molva), причем тут конструктор вообще? В коде флиппа shared_from_this вызывался до создания первого shared_ptr на этот объект. Следующий код вполне корректен в плане использования shared_from_this. Ну и да, естественно, создавать объекты A можно только с помощью new.
Код:
struct A : public boost::enable_shared_from_this<A>
{
        A()
        {
                boost::shared_ptr<A> pThis(this);
                this->shared_from_this();
        }
};

_________________
Когда работники зоопарка били крокодила, я увидел крокодиловы слезы.

» Добавлено: Пт Сен 30, 2011 7:05 pm
Gregs

avatar

  Цитировать Профиль  Сообщение    

добрый пирожок (Backslash), 2HeLL (Molva) прав, shared_from_this в конструкторе вызывать нельзя!
Flipp, а это:
Цитата:
Requires: enable_shared_from_this<T> ... *this must be a subobject of an instance t of type T . There must exist at least one shared_ptr instance p that owns t.

означает, что shared_from_this можно вызывать только у тех объектов, которые были созданы как shared_ptr.

_________________
семь раз подумай, один раз запость

» Добавлено: Вс Фев 03, 2013 12:09 pm
Duke

avatar

  Цитировать Профиль  Сообщение  e-mail  

А нельзя сразу использовать вектор? Зачем эти махинации? Или вообще можно универсальный список замутить, как в шарпе, например вот:
Warning!!! BydloCode is detected!
Скрытый текст

Код:
#ifndef _CSLIST_HPP
#define _CSLIST_HPP

#include <boost>
#include <vector>
#include <algorithm>

template <class> class csList
{
public:
typedef boost::shared_ptr<T> my_ptr_t;
typedef std::vector<my_ptr_t> my_vec_t;
private:
my_vec_t Items;

bool FCompare(my_ptr_t a, my_ptr_t b)
{
return *a < *b;
}

public:

csList()
{

}
csList(T& co)
{
Items.push_back(my_ptr_t(new T(co)));
}
void AddItem(T& co)
{
Items.push_back(my_ptr_t(new T(co)));
}
void AddRange(csList& in_list)
{
int count = in_list.Count();
for(int i = 0; i <count> n)
{
return *Items[n];
}
else return *(new T());
}
void Insert(int index, T& co)
{
if(index >= 0)
{
int count = (int)Items.size();

if(index == count)
{
Items.push_back(my_ptr_t(new T(co)));
return;
}
if(index <count>= 0) && (index < count))
{
Items.erase(Items.begin() + index);
}
}

}
bool Contains(T& co)
{
int count = (int)Items.size();
for(int i = 0; i < count; i++) if(*Items[i] == co) return true;
return false;
}

template <class> class SortCompare
{
N n;

public:
SortCompare(N _n){n = _n;}
bool operator ()(my_ptr_t a, my_ptr_t b)
{
T aa = *a;
T bb = *b;
return n.compare(aa, bb);
}
};

template <class>
void Sort(C c)
{
SortCompare<C> a(c);
sort(Items.begin(), Items.end(), a);
}

void Sort()
{
sort(Items.begin(), Items.end(), FCompare);
}
~csList()
{
Items.clear();
}
};

#endif


csList.hpp
 Описание:

Скачать
 Имя файла: csList.hpp  |  Размер файла:1,98 KB  |  Скачано:349 раз(а)

_________________

» Добавлено: Пн Фев 04, 2013 6:54 pm
добрый пирожокs

avatar

  Цитировать Профиль  Сообщение    

Gregor:

добрый пирожок (Backslash), 2HeLL (Molva) прав, shared_from_this в конструкторе вызывать нельзя!
Flipp, а это:
Цитата:
Requires: enable_shared_from_this<T> ... *this must be a subobject of an instance t of type T . There must exist at least one shared_ptr instance p that owns t.

означает, что shared_from_this можно вызывать только у тех объектов, которые были созданы как shared_ptr.


Gregor, в конструкторе A как раз создается первый инстанс shared_ptr<A> (т.к. this в теле конструктора - указатель на полностью проинициализированный объект, если только это не базовый класс, и мы не находимся в конструкторе базового класса - в этом случае очевидно, что мемберы производного класса еще не проинициализированы, но при этом мемберы базового класса вполне себе можно использовать):
Код:
boost::shared_ptr<A> pThis(this);
, и только потом вызвается shared_from_this. Другое дело, что это говнокод и он лишен всякого практического смысла, т.к. на выходе из конструктора очевидно будет вызван delete this и может случиться следующее:
1 - объект был создан с помощью new: оператор new вернет указатель на уже разрушенный объект (и кусок освобожденной памяти).
2 - объект создан на стеке: скорее всего получим поврежденный heap (т.к. вызываем delete для объекта, для которого не вызывали new), возможно будет выброшено исключение.
Если исходить из этих утверждений, то да, наверное не следует создавать shared_ptr на самого себя в конструкторе.

Gregor:
shared_from_this можно вызывать только у тех объектов, которые были созданы как shared_ptr.

Посмеялся над этим. Объекты создаются либо с помощью оператора new (как правило в куче, если только не перегружен оператор new для определенного класса (в этом случае память под объект может выделяться аллокатором), либо это inplace new (на указанном участке памяти)), либо автоматически на стеке (где память под объекты выделяется соответственно из стека), никакого "созданы как shared_ptr" не существует. shared_ptr лишь один из множества "умных указателей", который может использоваться для контроля времени жизни объекта.

_________________
Когда работники зоопарка били крокодила, я увидел крокодиловы слезы.

» Добавлено: Сб Фев 09, 2013 2:38 pm
Gregs

avatar

  Цитировать Профиль  Сообщение    

Backslash:

Посмеялся над этим. Объекты создаются либо с помощью оператора new (как правило в куче, если только не перегружен оператор new для определенного класса (в этом случае память под объект может выделяться аллокатором), либо это inplace new (на указанном участке памяти)), либо автоматически на стеке (где память под объекты выделяется соответственно из стека), никакого "созданы как shared_ptr" не существует. shared_ptr лишь один из множества "умных указателей", который может использоваться для контроля времени жизни объекта.

Я слоупок. Спасибо за ликбез про выделение памяти, кэп.
А если по делу, ты ведь понимаешь, что вызов shared_from_this() у объекта, над которым не владеет shared_ptr, ни к чему хорошему привести не может? К слову, нельзя этого сделать ровно по той же причине, по которой нельзя вызвать shared_from_this() внутри конструктора. По какой именно, думаю, догадаешься ты ведь у нас умный.

_________________
семь раз подумай, один раз запость

» Добавлено: Ср Окт 21, 2015 5:57 pm
Нaчaть нoвую тeму   Отвeтить нa тeму
Распечатать тему
Показать сообщения:   

 
Перейти:   
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете вкладывать файлы
Вы можете скачивать файлы


Powered by phpBB 0.99 beta © 2001, 2002 phpBB Group