как сделать "слепок" shared_ptr-ов и восстановиться с него?
От: sinmaster  
Дата: 13.09.08 12:23
Оценка:
привет.

никто не подскажет, каким образом можно забэкапить вектор умных указателей, чтобы потом восстановить по нему текущий? забэкапленный вектор указателей должен быть независимым (т.е. чтобы далее при изменении объектов текущего вектора объекты в забэкапленном векторе НЕ менялись). короче, сделать временный "слепок" надо, а потом восстановиться с него.

для полноты вопроса приведу код отражающий мой вопрос:
class Base{
protected:
  std::size_t _i;  
public:
  Base(std::size_t i):_i(i) { }
  virtual ~Base(){ }
  void setvalue(const std::size_t i){ _i = i; }
  std::size_t getvalue() const { return _i; }
}

class Derived1 : public Base{
public:
  Derived1(std::size_t i):Base(i){ }
};

class Derived2 : public Base{
public:
  Derived2(std::size_t i):Base(i){ }
};

class Foo{
  std::vector< boost::shared_ptr<Base> > objects_vector;
public:
  void fill(){
     objects_vector.push_back( boost::shared_ptr<Base>(new Derived1(1)) );
     objects_vector.push_back( boost::shared_ptr<Base>(new Derived1(2)) );
     objects_vector.push_back( boost::shared_ptr<Base>(new Derived2(3)) );
     ...
  }
  void modifyCurrentObjects(){
     for (std::size_t i = 0; i < objects_vector.size(); ++i){
       (objects_vector[i])->setvalue( rand()%10); //изменяем состояние объектов
     }
  }
  void execute(){
     std::vector< Base* > snapshot = dumpObjectsFromVector(); //как сделать? (1)
     modifyCurrentObjects(); //в objects_vector теперь объекты с измененными данными 
     objects_vector = snapshot; //восстанавливаем состояние объектов (2)
  }
  void test() const{
     for (std::size_t i = 0; i < objects_vector.size(); ++i){
       std::cout << objects_vector[i]->getvalue() << " ";
     }
  } 
};

////
int main(){

  Foo foo;
  foo.fill();
  foo.execute();
  foo.test(); //надо добиться того, чтобы вывел старые данные, то есть "1 2 3"  

  return 0;
}

подскажите, как это сделать? большое спасибо всем за помощь.
Re: как сделать "слепок" shared_ptr-ов и восстановиться с н
От: Юрий Жмеренецкий ICQ 380412032
Дата: 13.09.08 13:26
Оценка: +1
Здравствуйте, sinmaster, Вы писали:

S>привет.


S>никто не подскажет, каким образом можно забэкапить вектор умных указателей, чтобы потом восстановить по нему текущий? забэкапленный вектор указателей должен быть независимым (т.е. чтобы далее при изменении объектов текущего вектора объекты в забэкапленном векторе НЕ менялись). короче, сделать временный "слепок" надо, а потом восстановиться с него.


class Base
{
public:
  
  virtual Base* clone();

  /*...*/
};


?
Re[2]: как сделать "слепок" shared_ptr-ов и восстановиться
От: sinmaster  
Дата: 13.09.08 14:04
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>
ЮЖ>class Base
ЮЖ>{
ЮЖ>public:
  
ЮЖ>  virtual Base* clone();

ЮЖ>  /*...*/
ЮЖ>};
ЮЖ>


ЮЖ>?


идею понял, угу. пара вопросов:
1) вот так должно быть?
class Base{
public:
virtual ~Base() { }
virtual Base *clone() const = 0;
/* */
};
class Derived1 : public Base{
public:
virtual Base *clone() const {
return new Derived1(*this);
}
};
//аналогично для Derived2
все правильно?

2) можно ли как-то по методу clone() возвращать weak_ptr (или что-то похожее, малотребуемое к ресурсам и с простой логикой владения), далее закидываем их в вектор weak-ptr-ов, делаем наши дела как я выше расписал, а далее восстанавливаем наш вектор shared-ptr-ов на основе вектора weak-ptr-ов ? можно ли так?
в любом случае возвращать голые указатели по clone() не хочется
Re: как сделать "слепок" shared_ptr-ов и восстановиться с н
От: Qbit86 Кипр
Дата: 13.09.08 14:09
Оценка:
Здравствуйте, sinmaster, Вы писали:

S>никто не подскажет, каким образом можно забэкапить вектор умных указателей, чтобы потом восстановить по нему текущий? забэкапленный вектор указателей должен быть независимым (т.е. чтобы далее при изменении объектов текущего вектора объекты в забэкапленном векторе НЕ менялись). короче, сделать временный "слепок" надо, а потом восстановиться с него.


S>подскажите, как это сделать? большое спасибо всем за помощь.


Способов есть несколько. Вот один из них, инспирированный работой с C#.

Сделай свой класс immutable, неизменным. Это значит, что если пользователь захочет изменить поле твоего класса, то он должен будет вместо этого просто создать новый объект, передав ему в конструктор новое значение поля. Как-то так:
#include <boost/shared_ptr.hpp>

#include <cstddef> // std::size_t.
#include <cstdlib> // std::rand().
#include <iostream>
#include <vector>

class Base
{
private: // Зачем его делать protected?
  int i_;  
public:
  Base(int i) : i_(i) { }
  virtual ~Base() { }
public:
  int Value() const { return i_; }
  virtual Base const* Create(int i) const = 0;
};

// При переопределении функции Create() С++ позволяет изменить сигнатуру ковариантным образом.

class Derived1 : public Base
{
public:
  Derived1(int i) : Base(i) { }
  Derived1 const* Create(int i) const { return new Derived1(i); }
};

class Derived2 : public Base
{
public:
  Derived2(int i) : Base(i) { }
  Derived2 const* Create(int i) const { return new Derived2(i); }
};

class Foo{
  std::vector< boost::shared_ptr<Base const> > objects_;
public:
  void fill() {
    objects_.push_back( boost::shared_ptr<Base>(new Derived1(1)) );
    objects_.push_back( boost::shared_ptr<Base>(new Derived1(2)) );
    objects_.push_back( boost::shared_ptr<Base>(new Derived2(3)) );
  }
  void modifyCurrentObjects() {
    for (std::size_t i = 0; i != objects_.size(); ++i)
      objects_[i].reset( objects_[i]->Create(std::rand() % 10) );
  }
  void execute() {
    std::vector< boost::shared_ptr<Base const> > const snapshot(objects_.begin(), objects_.end());
    modifyCurrentObjects();
    objects_ = snapshot;
  }
  void test() const {
    for (std::size_t i = 0; i < objects_.size(); ++i)
      std::cout << objects_[i]->Value() << " ";
    std::cout << std::endl;
  }
};

int main()
{
  Foo foo;
  foo.fill();
  foo.execute();
  foo.test(); // 1 2 3

  return 0;
}
Глаза у меня добрые, но рубашка — смирительная!
Re[2]: как сделать "слепок" shared_ptr-ов и восстановиться
От: sinmaster  
Дата: 13.09.08 14:50
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Способов есть несколько. Вот один из них, инспирированный работой с C#.

//skipped

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

т.е. , грубо говоря, если у меня в инстанции foo лежит 10 объектов, метод execute содержит 100 изменений этих объектов, а сам этот метод вызывается 5 раз, то картина примерно следующая:

//способ с clone():
cоздастся 5*10 = 50 дополнительных объектов для бэкапа, по 10 при каждом вызове execute()
и после кажд. исполнения execute() мне надо будет делать _objects.swap(backup_snapshot);
//ваш способ:
также создастся 5*100 дополнительных объектов, по 100 при каждом вызове execute()
Re[3]: как сделать "слепок" shared_ptr-ов и восстановиться
От: sinmaster  
Дата: 13.09.08 14:54
Оценка:
блин, опечатался.

//способ с clone():
cоздастся 5*10 = 50 дополнительных объектов для бэкапа, по 10 при каждом вызове execute()
и после кажд. исполнения execute() мне надо будет делать _objects.swap(backup_snapshot);
//ваш способ:
создастся 5*100 = 500 дополнительных объектов, по 100 при каждом вызове execute()
Re[3]: как сделать "слепок" shared_ptr-ов и восстановиться
От: Юрий Жмеренецкий ICQ 380412032
Дата: 13.09.08 15:00
Оценка:
Здравствуйте, sinmaster, Вы писали:

S>идею понял, угу. пара вопросов:

S>1) вот так должно быть?
S>
S>class Base{
S>public:
S>virtual ~Base() { }
S>virtual Base *clone() const = 0;
S>/* */
S>};
S>class Derived1 : public Base{
S>public:
S>virtual Base *clone() const {
S>return new Derived1(*this);
S>}
S>};
S>//аналогично для Derived2
S>все правильно?
S>

S>2) можно ли как-то по методу clone() возвращать weak_ptr (или что-то похожее, малотребуемое к ресурсам и с простой логикой владения),

Если возвращать любой smart pointer, то теряется возможность использовать ковариантные возвращаемые значения(у Qbit86 в соседнем сообщении). Если это не нужно, то shared_ptr подойдет(а weak_ptr нет).

S>далее закидываем их в вектор weak-ptr-ов, делаем наши дела как я выше расписал, а далее восстанавливаем наш вектор shared-ptr-ов на основе вектора weak-ptr-ов ? можно ли так?

Так, только weak_ptr здесь не подойдет т.к. clone передает владение. А вообще это распространенный(в разумных пределах) прием: делаем копию, модифицируем, потом выполняем swap. В результате имеем strong exception guarantee.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.