Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Идиома copy-on-swap С++ / 25 сообщений из 39, страница 1 из 2
11.02.2015, 23:26
    #38877483
Станислав Клевцов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Здравствуйте.

Есть описание идиомы на WIKIPEDIA
https://ru.wikipedia.org/wiki/Идиома_copy-and-swap

Кто - нибудь может объяснить тоже самое, но только в двух словах и более простом языком ?
...
Рейтинг: 0 / 0
12.02.2015, 00:35
    #38877507
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Станислав Клевцов,

1) Проблема.
При реализации операторов присвоения, при присвоении поэлементно полей класса в определенный момент может возникнуть исключение (например нехватка памяти) и часть полей останется присвоенной, а часть нет.
Объект при этом может оказаться в несогласованном состоянии - часть полей относится к старому объекту, часть к новому. Часто при этом могут быть потеряны неосвобожденные указатели на кучу.

2) Решение.
Сначала создать временный объект, копию того из которого присваивается.
Если на этом этапе произойдет исключение, то текущий объект пока еще не изменен и несогласованности нет.
Потом производится обмен полей временного объекта с полями конечного объекта путем простого побайтового копирования. Такое копирование не может выбросить исключение и оно почти не вносит дополнительных расходов.
На завершающем этапе присвоения вызовется деструктор временного объекта и очистит поля ранее принадлежавшие конечному объекту.

Таким образом данное решение позволяет всегда иметь объекты в согласованном состоянии.
...
Рейтинг: 0 / 0
12.02.2015, 00:45
    #38877509
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Иными словами проблема высосана из пальца. И ее решение хоть и достаточно элегантно, но не имеет смысла.
...
Рейтинг: 0 / 0
12.02.2015, 01:18
    #38877514
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
White OwlИными словами проблема высосана из пальца
Это вполне реальная проблема.
Конечно с точки зрения С-шника, необходимость вручную убирать выделенную память не является проблемой.
Но в С++ концепция другая - главная цель создания С++ - переложить всю ручную работу на компилятор.
Данная идиома показывает как это сделать проще всего для конкретной задачи.
...
Рейтинг: 0 / 0
12.02.2015, 01:22
    #38877515
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Anatoly MoskovskyWhite OwlИными словами проблема высосана из пальца
Это вполне реальная проблема.
Конечно с точки зрения С-шника, необходимость вручную убирать выделенную память не является проблемой.
Но в С++ концепция другая - главная цель создания С++ - переложить всю ручную работу на компилятор.
Данная идиома показывает как это сделать проще всего для конкретной задачи.Вот я так и чувствовал что на мой фундамент начнут кивать...

Подразумевается что есть класс:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
class A {
   string *str1, *str2;
   A() {
      str1 = new string();
      str2 = new string();
   }

   A& operator=(const A & a) {
     str1 = new string(a.str1);  // can fail
     str2 = new string(a.str2);  // can fail
     return *this;
  }

  ~A() {
     delete str1;
     delete str2;
  }

  void set_data( ... ) {....} // do something
};



A a, b;
a.set_data ( );

try {
   b=a;
} catch (Exception e) {
   delete b;
}


И теперь, если одно из присвоений внутри operator=() упало, то в последней строке состояние b будет неопределенным. Было заполнено str1? str2? или еще что-то упало? В каком объеме надо очищать b?
Я правильно понимаю вашу проблему?
...
Рейтинг: 0 / 0
12.02.2015, 01:32
    #38877516
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
White OwlИ теперь, если одно из присвоений внутри operator=() упало, то в последней строке состояние b будет неопределенным. Было заполнено str1? str2? или еще что-то упало? В каком объеме надо очищать b?
Я правильно понимаю вашу проблему?
Да, обычно новички каждый раз заново придумывают как реализовать оператор =.
И чаще всего, как и в вашем случае, он неверно реализован.
Например, не удаляется предыдущее значение полей.
И прочее.
Чтобы не придумывать каждый раз, данная идиома показывает как тривиально реализовать =, который автоматически не имеет указанных проблем и заодно не требует перехвата исключений.
...
Рейтинг: 0 / 0
12.02.2015, 01:52
    #38877520
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Anatoly MoskovskyWhite OwlИ теперь, если одно из присвоений внутри operator=() упало, то в последней строке состояние b будет неопределенным. Было заполнено str1? str2? или еще что-то упало? В каком объеме надо очищать b?
Я правильно понимаю вашу проблему?
Да, обычно новички каждый раз заново придумывают как реализовать оператор =.
И чаще всего, как и в вашем случае, он неверно реализован.
Например, не удаляется предыдущее значение полей.
И прочее.
Чтобы не придумывать каждый раз, данная идиома показывает как тривиально реализовать =, который автоматически не имеет указанных проблем и заодно не требует перехвата исключений.Не требует? Точно?
То есть ты утверждаешь что если оператор присваивания переписать через copy-and-swap, то исключения возникнуть не смогут?
А исключения которые могут возникнуть внутри конструктора копирования (и по тем-же самым причинам) ты в расчет не принимаешь?
...
Рейтинг: 0 / 0
12.02.2015, 02:08
    #38877521
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
White OwlТо есть ты утверждаешь что если оператор присваивания переписать через copy-and-swap, то исключения возникнуть не смогут?
Могут.
White OwlА исключения которые могут возникнуть внутри конструктора копирования (и по тем-же самым причинам) ты в расчет не принимаешь?
Да, не принимаю, т.к. это забота конструктора копирования (который по-любому нужно реализовать если требуется оператор=), и к тому же в правильно написанном конструкторе компилятор сам заботится о исключениях.
...
Рейтинг: 0 / 0
12.02.2015, 02:47
    #38877525
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Anatoly MoskovskyWhite OwlТо есть ты утверждаешь что если оператор присваивания переписать через copy-and-swap, то исключения возникнуть не смогут?
Могут.Я рад что ты это понимаешь.

Anatoly MoskovskyWhite OwlА исключения которые могут возникнуть внутри конструктора копирования (и по тем-же самым причинам) ты в расчет не принимаешь?
Да, не принимаю, т.к. это забота конструктора копирования (который по-любому нужно реализовать если требуется оператор=), А вот это очень даже плохо. На этом вы, любимые мои сипипифилы, и горите.

Во первых, никто не гарантирует что конструктор копирования написан правильно (а не точно так как я показал в примере кривого оператора присваивания).
Во вторых, для copy-and-swap надо еще написать правильный метод swap. Что тоже не всегда тривиально.
В третьих, даже если конструктор копирования и swap() написаны правильно - конструктор все равно может упасть. И значит каждый a=b; надо оборачивать в try{}catch (или ловить исключение выше по стеку).
Это были минусы copy-and-swap. В плюсах:
- при наличии обоих методов: конструктора копирования и оператора присваивания, если один метод вызывает другой то жить чуть проще становится. Что однако нивелируется необходимостью написания метода swap()...
- если a=b все-же упала, то мы точно знаем что a это "пустой" объект.

Однако! Если правильно написать operator=() то и проблемы несогласованного состояния тоже никогда не будет. А если неправильно написать конструктор копирования, то проблема несогласованного состояния все равно возникнет.


Вывод: используешь ты этот патерн или нет разницы никакой нет. Без него тебе надо продуманно писать operator=() и конструктор копирования. С ним тебе надо продуманно писать конструктор копирования и swap(). Работы в итоге получается практически одинаково. Упасть на a=b можно в обоих случаях и с одинаковым результатом.
...
Рейтинг: 0 / 0
12.02.2015, 03:11
    #38877527
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
White OwlВо первых, никто не гарантирует что конструктор копирования написан правильно (а не точно так как я показал в примере кривого оператора присваивания).
Написать конструктор правильно намного проще, чем присвоение.

White OwlВо вторых, для copy-and-swap надо еще написать правильный метод swap. Что тоже не всегда тривиально.
Нет. Всегда тривиально.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
friend void swap(T& a, T& b)
{
	using std::swap;
	swap(a.f1, b.f1);
	swap(a.f2, b.f2);
	swap(a.f3, b.f3);
}


Если это нетривиально, то что тогда тривиально ))
White OwlВ третьих, даже если конструктор копирования и swap() написаны правильно - конструктор все равно может упасть. И значит каждый a=b; надо оборачивать в try{}catch (или ловить исключение выше по стеку).
Нет. Не надо оборачивать ничего. Исключения ловятся там где это задумано по дизайну приложения, а не в операторе присвоения из-за неумения написать его правильно - это и есть цель которая достигается данной идиомой

White OwlВывод: используешь ты этот патерн или нет разницы никакой нет. Без него тебе надо продуманно писать operator=() и конструктор копирования. С ним тебе надо продуманно писать конструктор копирования и swap(). Работы в итоге получается практически одинаково. Упасть на a=b можно в обоих случаях и с одинаковым результатом.
Садитесь два. Изучайте заново материал ))

ЗЫ. White Owl, критика всегда уместна. Критиковать можно даже то, в чем не разбираешься. Но не надо облекать это в форму советов бывалого и тем более заниматься дартаньянизмом :)
...
Рейтинг: 0 / 0
12.02.2015, 07:10
    #38877549
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Anatoly MoskovskyWhite OwlВо первых, никто не гарантирует что конструктор копирования написан правильно (а не точно так как я показал в примере кривого оператора присваивания).
Написать конструктор правильно намного проще, чем присвоение.Почему? В чем разница?

Anatoly MoskovskyWhite OwlВо вторых, для copy-and-swap надо еще написать правильный метод swap. Что тоже не всегда тривиально.
Нет. Всегда тривиально.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
friend void swap(T& a, T& b)
{
	using std::swap;
	swap(a.f1, b.f1);
	swap(a.f2, b.f2);
	swap(a.f3, b.f3);
}


Если это нетривиально, то что тогда тривиально ))Тривиально это отсутствие метода. А в данном случае нетривиально то, что надо не забыть перечислить все поля. И это только в минимуме, если используемые ресурсы это исключительно куски памяти. А если копируемые ресурсы что-то более сложное (ну хоть хендлы на файлы или мютексы) то простым std::swap уже не отделаешься.

Anatoly MoskovskyWhite OwlВ третьих, даже если конструктор копирования и swap() написаны правильно - конструктор все равно может упасть. И значит каждый a=b; надо оборачивать в try{}catch (или ловить исключение выше по стеку).
Нет. Не надо оборачивать ничего. Исключения ловятся там где это задумано по дизайну приложения, а не в операторе присвоения из-за неумения написать его правильно - это и есть цель которая достигается данной идиомойХорошо. Вот в этом посте 17253298 , я показал не правильный код. Покажи мне правильный код пожалуйста.
Приведи правильный код класса который никогда не сможет упасть на присвоении.

Anatoly MoskovskyЗЫ. White Owl, критика всегда уместна. Критиковать можно даже то, в чем не разбираешься. Но не надо облекать это в форму советов бывалого и тем более заниматься дартаньянизмом :)Cura te ipsum
...
Рейтинг: 0 / 0
12.02.2015, 11:46
    #38877802
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
White OwlAnatoly MoskovskyНаписать конструктор правильно намного проще, чем присвоение.Почему? В чем разница?
1) в конструкторе не надо очищать старые значения (что уже проще)
2) при исключении в конструкторе, автоматически вызываются деструкторы тех полей, которые инициализированы на момент исключения (что намного проще, чем руками откатывать значения в =)

White OwlТривиально это отсутствие метода. А в данном случае нетривиально то, что надо не забыть перечислить все поля. И это только в минимуме, если используемые ресурсы это исключительно куски памяти. А если копируемые ресурсы что-то более сложное (ну хоть хендлы на файлы или мютексы) то простым std::swap уже не отделаешься.
Если swap не работает на одном из полей, то в такой объект вообще нельзя присваивать.
Хотя в частности ваш пример с хендлами такого ограничения не имеет - ничего не мешает делать хендлу swap.
White OwlПриведи правильный код класса который никогда не сможет упасть на присвоении.
Господи, ну нет такой задачи не упасть. Задача - при исключении оставить объект в согласованном состоянии, чтобы после перехвата исключения где-то там наверху можно было продолжить работу с объектом.
...
Рейтинг: 0 / 0
12.02.2015, 11:49
    #38877809
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
White OwlА в данном случае нетривиально то, что надо не забыть перечислить все поля.
А также не забыть включить компьютер, сохранить файл перед компиляцией, и другие нетривиальные действия
...
Рейтинг: 0 / 0
12.02.2015, 13:20
    #38877957
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Станислав КлевцовЗдравствуйте.

Есть описание идиомы на WIKIPEDIA
https://ru.wikipedia.org/wiki/Идиома_copy-and-swap

Кто - нибудь может объяснить тоже самое, но только в двух словах и более простом языком ?


По-моему, там всё предельно понятно расписано.
Единственно, что текст немного устарел, поскольку спецификация throw уже объявлена устаревшей.
...
Рейтинг: 0 / 0
12.02.2015, 13:25
    #38877970
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Anatoly MoskovskyWhite OwlВо первых, никто не гарантирует что конструктор копирования написан правильно (а не точно так как я показал в примере кривого оператора присваивания).
Написать конструктор правильно намного проще, чем присвоение.



На самом деле после появления placement new конструктор стал более похож на оператор присваивания, и они почти сравнялись.
Почти -- потому что по стандарту программирс обязан после вызова placement new вызвать сам руками деструктор объекта.
Но всё равно никто не запрещает возложить на конструктор такую же семантику, как на оператор присваивания, и не вызывать деструктор.
...
Рейтинг: 0 / 0
12.02.2015, 13:30
    #38877980
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
White OwlAnatoly Moskovskyпропущено...

Написать конструктор правильно намного проще, чем присвоение.Почему? В чем разница?



Изначально в языке у них была разная семантика.

Конструктор инициализирует объект, а это значит, что до этого объекта в этой памяти (*this) не было, и его не надо деинициализировать.

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

Кроме этого, конструктор копирования нельзя вызывать от самого себя (потому что бессмысленно, в принципе -- можно, но на это никто не закладывается), а оператор присваивания самому себе вполне может быть.
...
Рейтинг: 0 / 0
12.02.2015, 15:11
    #38878154
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
MasterZivНа самом деле после появления placement new конструктор стал более похож на оператор присваивания, и они почти сравнялись.
Почти -- потому что по стандарту программирс обязан после вызова placement new вызвать сам руками деструктор объекта.
Но всё равно никто не запрещает возложить на конструктор такую же семантику, как на оператор присваивания, и не вызывать деструктор

Введение placement new ничего не добавило принципиального. С обычным new вызов деструктора тоже вручную производится - оператором delete

И это все никакого отношения к обсуждаемому вопросу не имеет.
...
Рейтинг: 0 / 0
12.02.2015, 15:46
    #38878226
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Anatoly MoskovskyMasterZivНа самом деле после появления placement new конструктор стал более похож на оператор присваивания, и они почти сравнялись.
Почти -- потому что по стандарту программирс обязан после вызова placement new вызвать сам руками деструктор объекта.
Но всё равно никто не запрещает возложить на конструктор такую же семантику, как на оператор присваивания, и не вызывать деструктор

Введение placement new ничего не добавило принципиального. С обычным new вызов деструктора тоже вручную производится - оператором delete

И это все никакого отношения к обсуждаемому вопросу не имеет.

Подумай лучше ...
...
Рейтинг: 0 / 0
12.02.2015, 22:38
    #38878583
Станислав Клевцов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Anatoly MoskovskyСтанислав Клевцов,

1) Проблема.
При реализации операторов присвоения, при присвоении поэлементно полей класса в определенный момент может возникнуть исключение (например нехватка памяти) и часть полей останется присвоенной, а часть нет.
Объект при этом может оказаться в несогласованном состоянии - часть полей относится к старому объекту, часть к новому. Часто при этом могут быть потеряны неосвобожденные указатели на кучу.

2) Решение.
Сначала создать временный объект, копию того из которого присваивается.
Если на этом этапе произойдет исключение, то текущий объект пока еще не изменен и несогласованности нет.
Потом производится обмен полей временного объекта с полями конечного объекта путем простого побайтового копирования. Такое копирование не может выбросить исключение и оно почти не вносит дополнительных расходов.
На завершающем этапе присвоения вызовется деструктор временного объекта и очистит поля ранее принадлежавшие конечному объекту.

Таким образом данное решение позволяет всегда иметь объекты в согласованном состоянии.

Спасибо, Анатолий и White Owl ! Стало намного понятнее. Еще раз спасибо.
...
Рейтинг: 0 / 0
13.02.2015, 16:30
    #38879303
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Несколько мыслей.

Интересно насколько нужно много (или мало) внимания уделять вообще самому факту
возникновения подобной ситуации. Память может закончится в любой момент. Это факт.
Но сколько мы должны потратить человеко-лет чтобы весь код покрыть подобной идеомой?
Или отрефакторить.
...
Рейтинг: 0 / 0
13.02.2015, 16:48
    #38879326
RWolf
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
mayton,

Исключение здесь необязательно связано с памятью, это может быть неудачное завершение транзакции, захват/освобождение ресурса, ошибка RPC и т.п.
...
Рейтинг: 0 / 0
13.02.2015, 17:01
    #38879333
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
maytonИнтересно насколько нужно много (или мало) внимания уделять вообще самому факту
возникновения подобной ситуации. Память может закончится в любой момент. Это факт.

Исключения выкидываются далеко не только по нехватке памяти и прочих ресурсов.
При присвоении полей могут возникать и "прикладные" исключения.

maytonНо сколько мы должны потратить человеко-лет чтобы весь код покрыть подобной идеомой?
Или отрефакторить.
Так можно и не переделывать, если вас и так устраивала надежность приложения до того как вы про эту идиому узнали ))
...
Рейтинг: 0 / 0
13.02.2015, 18:02
    #38879396
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Столько заморочек только чтобы присваивать сами объекты вместо указателей на них... Для
кого, спрашивается смарт-указатели в стандарт ввели?..
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
13.02.2015, 18:28
    #38879419
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Dimitry Sibiryakov,

А если вам нужны два разных объекта, как тут смартуказатели помогут?
...
Рейтинг: 0 / 0
13.02.2015, 18:36
    #38879423
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Идиома copy-on-swap С++
Anatoly MoskovskyА если вам нужны два разных объекта, как тут смартуказатели
помогут?
Точно так же как в сабже: если создание нового объекта обломилось во время работы
копи-конструктора, указатель не присвоится и компилятор с деструктором позаботятся о
зачистке обломков.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Идиома copy-on-swap С++ / 25 сообщений из 39, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]