Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Копирование объектов в Multithreading


Автор: exploys 20.10.2010, 01:22
Упрощенный пример
Код


class MyClassA
{
 public:
 class MyClassB
 {
  int Par1;
  char Par2;
 }

 int ParA;
 MyClassB *MyObjectsB;
 unsigned int CountMyObjects;

 void initFromFile(string fileName)
 { .... }
};

MyClassA objectA1;

int main(int argc, char* argv[])
{
 objectA1.initFromFile("fileName");
}

void MyFunc(void)
{
 MyClassA objectA2;
 objectA2 = objectA1; 
}


И собственно два вопроса:
1. Как лучше сделать чтобы при objectA2 = objectA1; копировались не указатели на MyObjectsB, а создавалась собственная копия MyObjectsB для objectA2. Перегрузкой оператора =, отдельной функцией или как-то ещё.
2. При условии, что функция void MyFunc(void) будет вызываться из множества потоков что следует исправить в коде?

Подскажите что исправить или посоветуйте литературу, а если и то и то, то вообще будет шикарно.


Автор: Rad87 20.10.2010, 08:15
вероятно, описать все это в конструкторе копирования

Автор: xvr 20.10.2010, 09:05
Цитата(exploys @ 20.10.2010,  01:22)
1. Как лучше сделать чтобы при objectA2 = objectA1; копировались не указатели на MyObjectsB, а создавалась собственная копия MyObjectsB для objectA2. Перегрузкой оператора =, отдельной функцией или как-то ещё.

Оператор присваивания и конструктор копирования
Цитата

2. При условии, что функция void MyFunc(void) будет вызываться из множества потоков что следует исправить в коде?

Целиком зависит от содержимого этой функции (т.е. от того самого оператора присваивания и конструктора копирования).
Самый универсальный способ - критическая секция (но и самый не эффективный по производительности)

Автор: GremlinProg 20.10.2010, 10:34
ну да, вот, кстати xvr тут где-то приводил вариант прокси с критической секцией,
удобнее похоже и не придумать

а вот по производительней можно использовать дроссель из семафора,
который будет перекрываться полностью при изменении каких-либо указателей (критические изменения в объекте),
или просто приоткрываться для определенного потока, если надо его только скопировать

единственное, что тут надо предусмотреть, чтобы полное перекрытие было защищено критической секцией,
чтобы несколько потоков не могли одновременно вносить критические изменения в объект

если сильно интересно, то почитать об этом можно у Харта, например: http://www.williamspublishing.com/Books/5-8459-0879-5.html

Автор: exploys 20.10.2010, 20:40
Спасибо за подсказки.

Создал функцию глубокого копирования  void Copy(MyClassA src) и конструктор копирования использующий данную функцию. Здесь все понятно. 

Вопрос для полноты понимания: как перегрузить оператор = для глубокого копирования (чтобы не перечислять все члены класса, а только те которые нужно скопировать по указателям, как в конструкторе копирования)?
Пробовал не получается.

Код


class MyClassA
{
 public:
 class MyClassB
 {
  int Par1;
  char Par2;
 }
 int ParA;
 MyClassB *MyObjectsB;
 unsigned int CountMyObjects;
 void initFromFile(string fileName)
 { .... }

 // Глубокое копирование
 void Copy(MyClassA src)
 {
  // поверхностное копирование
  *this = src;

  // глубокое копирование массива MyObjectsB[]
  this->MyObjectsB = new MyClassB [src.CountMyObjects];
  for (unsigned int indexObjectsB = 0; indexObjectsB < src.CountMyObjects; indexObjectsB ++)
   this->MyObjectsB[indexObjectsB ] = src.MyObjectsB[indexObjectsB ];
 }

 // Конструктор копирования с глубоким копированием
 MyClassA::MyClassA(MyClassAconst& src)
 {
   Copy(src);
 }
};

MyClassA objectA1;
int main(int argc, char* argv[])
{
 objectA1.initFromFile("fileName");
}
void MyFunc(void)
{
 MyClassA objectA2;
 objectA2 = objectA1;  // Поверхностное копирование
 objectA2.Copy(objectA1);  // Глубокое копирование
 MyClassA objectA3 = objectA1; // Глубокое копирование
}



Цитата(GremlinProg @  20.10.2010,  08:34 Найти цитируемый пост)

если сильно интересно, то почитать об этом можно у Харта, например: http://www.williamspublishing.com/Books/5-8459-0879-5.html 

Спасибо буду изучать.
А не подскажите как найти "вариант прокси с критической секцией от xvr"?

Автор: GremlinProg 20.10.2010, 22:33
Цитата(exploys @  20.10.2010,  22:40 Найти цитируемый пост)
как найти "вариант прокси с критической секцией от xvr"?

1. нажать "поиск"
2. ввести ключевое слово proxy
3. ввести в "фильтр по имени пользователя" xvr
4. нажать "найти"

Автор: xvr 20.10.2010, 23:39
http://forum.vingrad.ru/index.php?showtopic=303899&view=findpost&p=2173775

Автор: exploys 29.11.2010, 10:45
Спасибо. Классная штука.
А при перегрузке оператора = обязательно придется прописывать копирование каждой переменной или можно как-то их скопом скопировать? (а затем уже с нужными объектами провести глубокое копирование)

Автор: xvr 29.11.2010, 13:20
Цитата(exploys @  29.11.2010,  10:45 Найти цитируемый пост)
А при перегрузке оператора = обязательно придется прописывать копирование каждой переменной или можно как-то их скопом скопировать?
В очень редких случаях можно сделать memcpy(this,other,sizeof(*this));. Но это очень опасно, и если есть сомнения, то лучше так не делать!


Автор: exploys 1.12.2010, 11:33
Цитата(xvr @ 29.11.2010,  11:20)
Цитата(exploys @  29.11.2010,  10:45 Найти цитируемый пост)
А при перегрузке оператора = обязательно придется прописывать копирование каждой переменной или можно как-то их скопом скопировать?
В очень редких случаях можно сделать memcpy(this,other,sizeof(*this));. Но это очень опасно, и если есть сомнения, то лучше так не делать!

Я тоже подумал, что это некий костыль. А адекватного способа так и не нашел.
Т.е. либо полностью отдавать на откуп компилятору который почленно произведет поверхностное копирование. Либо делать глубокое, но уже самому почленно все прописывать. Оба варианта не всегда подходят.
Как вариант использовать умные указатели и контейнеры.

Автор: GremlinProg 1.12.2010, 11:37
Цитата(exploys @  1.12.2010,  13:33 Найти цитируемый пост)
А адекватного способа так и не нашел

адекватный - не переписывать оператор =
в этом случае все данные копируются почленно автоматом

Добавлено @ 11:45
если надо совместить почленное и глубокое копирование, то используется наследование:
Код

class B : public A{
  ...
  B&operator = ( const B&Src ){
    static_cast< &A >( *this ) = static_cast< const &A >( Src );
    //  ...глубокое копирование
    return *this;
  }
  ...
};

в классе A должны быть объявлены все данные для почленного копирования,
в классе A не должен быть переписан оператор =

Добавлено @ 11:50
кстати, тема подходит больше для раздела http://forum.vingrad.ru/forum/c-c++general-questions.html, перенести?

хотя, ладно, раз Multithreading, пусть тут живет

Автор: exploys 10.12.2010, 17:36
Спасибо, то что нужно smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)