Russian Qt Forum

Программирование => С/C++ => Тема начата: AzazelloAV от Июнь 21, 2017, 19:25



Название: c++ 11/14 vs "старый c++"
Отправлено: AzazelloAV от Июнь 21, 2017, 19:25
Данный пост не спрашивает никаких решений. Считайте это рассуждения вслух - кто как.

Классика RAII:
Код:
class Test
{
public:
    Test() { m_data = new Data; }
   ~Test() { delete mData; }
private:
    Data* m_data = 0;
}

По новому RAII:
Код:
class Test
{
public:
    Test();
   ~Test() = default
private:
    std::unique_ptr<Data> m_data;
    or
    QScopedPointer<Data> m_data;
}

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

Отказался от использования unique_ptr для таких (именно таких случаях, пусть это будет PImpl)
1.  Отсутсвует подсветка синтаксиса для m_data
2. Дебаг по коду позволяет ознакомиться с вырвиглазным кодом stl

Сразу отвечу противникам - даже если вы пропустили ваш делете, никто сейчас не программирует без профилировщика и не заметить пропуск такого явного удаления просто невозможно, причем в самом начале.

P.S. Пользуюсь ништяками c++11 давно.


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Авварон от Июнь 21, 2017, 20:18
1. Лечится включением шланг модели кода
2. Должно лечиться gdb pretty printers, нет?

Ну а так, unique_ptr exception-safe, а ручной Pimpl нет (например, тров в конструкторе после new)


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Igors от Июнь 22, 2017, 08:27
Причем тут подсветка если ф-ционал разный.
Код:
    std::unique_ptr<Data> m_data;
    or
    QScopedPointer<Data> m_data;
Эти варианты неравноценны. QScopedPointer можно свободно копировать и отдавать по значению, а unique_ptr нет.

Вообще иметь unique_ptr членом как-то не очень, есть довольно стойкий рефлекс что оператор = и конструктор копирования принимают константные аргументы, а здесь это не так. Выносить моск ради жалкого delete - не вижу смысла


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: AzazelloAV от Июнь 22, 2017, 10:33
1. Лечится включением шланг модели кода
2. Должно лечиться gdb pretty printers, нет?

Поясните подробней.
И, кстати, не всегда же мы в одной среде сидим, в т.ч. в  разных ОС.

Ну а так, unique_ptr exception-safe, а ручной Pimpl нет (например, тров в конструкторе после new)

Согласен с вашим примером. НО, это только единственный пример, который можно привести.

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


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: AzazelloAV от Июнь 22, 2017, 10:35
Цитировать
Эти варианты неравноценны. QScopedPointer можно свободно копировать и отдавать по значению, а unique_ptr нет.

Вообще иметь unique_ptr членом как-то не очень, есть довольно стойкий рефлекс что оператор = и конструктор копирования принимают константные аргументы, а здесь это не так. Выносить моск ради жалкого delete - не вижу смысла

Простите, но вообще ничего не понял.


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Авварон от Июнь 22, 2017, 12:02

Поясните подробней.
И, кстати, не всегда же мы в одной среде сидим, в т.ч. в  разных ОС.
Не, ну если у вас не креатор, то могу советовать погуглить как починить вашу иде:) А так, иде, не умеющая в вумные указатели - не нужна:)
А так, есть питоновские скрипты для gdb, которые "учат" его разворачивать умные указатели как обычные (без кишков). Как их подключить к иде я сходу не скажу (даже для креатора, давно это было). Вроде бы, под линухом достаточно поставить пакет. Под вин/мак вообще хз.

Согласен с вашим примером. НО, это только единственный пример, который можно привести.
Ну, мой пример выстрадан болью, а ваши надуманы:)

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

Почему нет? (Абстрагируемся о том, что исключения вообще с Qt кодом не дружат (я уже давно не пишу на Qt, к сожалению)). Это единственный способ сообщить об ошибке в конструкторе. Альтернативой будет только богомерзкий метод bool init(); который можно внезапно забыть вызвать. Или вызвать дважды. В общем, вы поняли, придётся писать много документации о том, как использовать ваш класс. Вместо банального инстанцирования.


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: ssoft от Июнь 22, 2017, 12:55
Отказался от использования unique_ptr для таких (именно таких случаях, пусть это будет PImpl)
...

Программировать можно как угодно, лишь бы программа работала корректно).
А вот для ее дальнейшего сопровождения - это создает существенные трудности, даже если программа твоя.

В случае raw указателя ( Data * ) невозможно с ходу понять, что имеется в виду - значение, массив значений, полюс ассоциативной связи, композитная агрегация, совместная агрегация. Что?
Использование std::unique_ptr хоть как-то ограничивает этот перечень, не говоря уже о неявном new/delete.

Даже стандарт С++11/14/17 не доработан до такой степени, чтобы можно было четко отделять мух от котлет

Код
class Test
{
public:
   Test();
   ~Test() = default
private:
   Attribute< Data > m_attribute; // данные, не участвующие в ассоциативных связях
   Unique<Data> m_unique; // полюс ассоциативной связи копозитной агрегации (участник ассоциативных связей)
   Shared<Data> m_shared; // полюс ассоциативной связи обобщенной агрегации (участник ассоциативных связей)
   Assocc<Data> m_assocc; // полюс ассоциативной связи, не являющейся агрегацией (участник ассоциативных связей)
}


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Авварон от Июнь 22, 2017, 13:13
Вместо Assocc можно использовать ссылку (std::reference_wrapper)
Вместо Attribute - value-based классы.


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Igors от Июнь 22, 2017, 13:13
полюс ассоциативной связи,
А что это? Расскажите. Спасибо

Использование std::unique_ptr хоть как-то ограничивает этот перечень, не говоря уже о неявном new/delete.
Думаю ключевое слово "хоть как-то". Да, заявили что владеем, отвечаем за создание/удаление. Другие достижения? (не наблюдаю)


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: ssoft от Июнь 22, 2017, 13:46
Вместо Assocc можно использовать ссылку (std::reference_wrapper)
Вместо Attribute - value-based классы.

В простейшем случае можно, а в общем недостаточно).

Например, для обобщенной агрегации в качестве ссылки нужно бы использовать weak_ptr. Даже для композитной агрегации может потребоваться использование связки shared_ptr/weak_ptr вместо unique_ptr/reference_wrapper.


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: ssoft от Июнь 22, 2017, 14:13
полюс ассоциативной связи,
А что это? Расскажите. Спасибо

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

Частным случаем ассоциаций являются биполярные ассоциации.
Частным случаем биполярной ассоциации является ассоциация агрегации (отношение Часть/Целое). Целое определяет время жизни Части.
Со стороны Целого полюс ассоциативной может быть либо unique (уникальная или композитная агрегация), либо shared (обобщенная агрегация).
Со стороны Части может либо не быть полюса, либо быть none (полюс не агрегации).

Хотя в стандарт и ввели unique_ptr и shared_ptr, но кроме названий ничего общего полюсами уникальной (композитной) и обобщенной агрегации они не имеют.
При этом они могут быть использованы при реализации этих самых полюсов ассоциативных связей (наравне с raw указателем)) ).


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Авварон от Июнь 22, 2017, 14:22
Частным случаем биполярной ассоциации является ассоциация агрегации (отношение Часть/Целое). Целое определяет время жизни Части.

Кажется, тут вы врёте. Из вики:
Цитировать
Агрегация (агрегирование по ссылке) — отношение «часть-целое» между двумя равноправными объектами, когда один объект (контейнер) имеет ссылку на другой объект. Оба объекта могут существовать независимо: если контейнер будет уничтожен, то его содержимое — нет.
Цитировать
Композиция (агрегирование по значению) — более строгий вариант агрегирования, когда включаемый объект может существовать только как часть контейнера. Если контейнер будет уничтожен, то и включённый объект тоже будет уничтожен.
Цитировать
Aggregation differs from ordinary composition in that it does not imply ownership. In composition, when the owning object is destroyed, so are the contained objects. In aggregation, this is not necessarily true


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Авварон от Июнь 22, 2017, 14:34
На самом деле, не уверен, что отношения агрегации/композиции должны быть частью стандарта.
Вот например, композиция один ко-многим может быть реализована десятком способов:
Код:
class Whole
{
    std::vector<Part> parts0;
    std::vector<std::unique_ptr<Part>> parts1;
    std::deque<std::unique_ptr<Part>> parts2;
    std::map<PartId, std::unique_ptr<Part>> parts5;
    std::unordered_map<PartId, std::unique_ptr<Part>> parts6;
    // ...
};


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Igors от Июнь 22, 2017, 15:02
Экземпляр ассоциации (связь) состоит из полюсов, связанных с объектами.
Часто ассоциативная связь реализуется в виде, когда её полюсы принадлежат одному и более объектам, участвующим в ассоциативной связи.
Так и не понял что такое (или где) "полюс". Ну да ладно, все равно спасибо

Вот shared_ptr имеет weak_ptr, полезная вещь, по крайней мере четко видно что владелец извне. А почему unique_ptr не имеет подобного? Если его надо где-то задействовать - выходит отдавай голый. Тогда за что боролись?


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: ssoft от Июнь 22, 2017, 15:23
Так и не понял что такое (или где) "полюс". Ну да ладно, все равно спасибо

Полюс - это значение, реализующее связь с объектом (ссылка, указатель, сам экземпляр объекта).

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


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: AzazelloAV от Июнь 22, 2017, 15:27

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

Частным случаем ассоциаций являются биполярные ассоциации.
Частным случаем биполярной ассоциации является ассоциация агрегации (отношение Часть/Целое). Целое определяет время жизни Части.
Со стороны Целого полюс ассоциативной может быть либо unique (уникальная или композитная агрегация), либо shared (обобщенная агрегация).
Со стороны Части может либо не быть полюса, либо быть none (полюс не агрегации).

Хотя в стандарт и ввели unique_ptr и shared_ptr, но кроме названий ничего общего полюсами уникальной (композитной) и обобщенной агрегации они не имеют.
При этом они могут быть использованы при реализации этих самых полюсов ассоциативных связей (наравне с raw указателем)) ).

Это какой то адский треш. Я всегда думал, что патерны придумали, чтобы разрабочикам было легче общатся. Не "делаю то-то, то-то, то-то, то-то", а использую петерн "название". Но со временем ситуация изменилась. Не патерны для прогеров, а прогеры для патернов. Теперь мне их хоть раз в пол года повторяй. И что самое инетересно - у всех они уже на подсознательном уровне. Проще это сделать, чем заучить вышенаписанное.


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Авварон от Июнь 22, 2017, 15:32
Это какой то адский треш. Я всегда думал, что патерны придумали, чтобы разрабочикам было легче общатся. Не "делаю то-то, то-то, то-то, то-то", а использую петерн "название". Но со временем ситуация изменилась. Не патерны для прогеров, а прогеры для патернов. Теперь мне их хоть раз в пол года повторяй. И что самое инетересно - у всех они уже на подсознательном уровне. Проще это сделать, чем заучить вышенаписанное.

Ну это просто термины дурацкие и незапоминающиеся (я до сих пор не могу запомнить кто сильнее - композиция или агрегация). То ли дело в uml - закрашенный ромбик (композиция) сильнее незакрашенного (агрегация)


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: AzazelloAV от Июнь 22, 2017, 15:49

Почему нет? (Абстрагируемся о том, что исключения вообще с Qt кодом не дружат (я уже давно не пишу на Qt, к сожалению)). Это единственный способ сообщить об ошибке в конструкторе. Альтернативой будет только богомерзкий метод bool init(); который можно внезапно забыть вызвать. Или вызвать дважды. В общем, вы поняли, придётся писать много документации о том, как использовать ваш класс. Вместо банального инстанцирования.

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


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: ssoft от Июнь 22, 2017, 15:56
Частным случаем биполярной ассоциации является ассоциация агрегации (отношение Часть/Целое). Целое определяет время жизни Части.
Кажется, тут вы врёте. Из вики:
Цитировать
Агрегация (агрегирование по ссылке) — отношение «часть-целое» между двумя равноправными объектами, когда один объект (контейнер) имеет ссылку на другой объект. Оба объекта могут существовать независимо: если контейнер будет уничтожен, то его содержимое — нет.
Цитировать
Композиция (агрегирование по значению) — более строгий вариант агрегирования, когда включаемый объект может существовать только как часть контейнера. Если контейнер будет уничтожен, то и включённый объект тоже будет уничтожен.
Цитировать
Aggregation differs from ordinary composition in that it does not imply ownership. In composition, when the owning object is destroyed, so are the contained objects. In aggregation, this is not necessarily true

В чем расхождение?
Если часть является композитом целого, то удаление целого означает удаление части. Если агрегатом, то часть не удаляется (хотя часть бывает целесообразно удалять часть при удалении всех связанных экземпляров целого).
И в википедии не вполне корректные определения, лучше пользоваться определениями спецификации UML http://www.omg.org/spec/UML/ (http://www.omg.org/spec/UML/), http://www.uml-diagrams.org/association.html (http://www.uml-diagrams.org/association.html)

Вместо терминов агрегация, композиция, как видов ассоциаций, к концам ассоциаций целесообразнее применять понятия уникальная агрегация (unique), совместная агрегация (shared), не агрегация (none).
Сам экземпляр ассоциативной связи Link является совокупностью всех концов. Один конец не определяет ассоциативную связь.

Нет никакого обязательного соответствия, что агрегация это только ссылка, указатель или что-то еще; или что композиция это только inplace значение (расположенное непосредственно в экземпляре целого), и не может быть реализовано посредством raw, unique_ptr, shared_ptr, reference_wrapper или любого другого указателя, контейнера или ссылки.


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: panAlexey от Июнь 24, 2017, 09:18
ИМХО 2-й пример добавляет работы процессору и его надо использовать там, где это действительно необходимо.
Такая избыточность должна быть использована с умом.


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: _Bers от Июнь 24, 2017, 21:14
ИМХО 2-й пример добавляет работы процессору и его надо использовать там, где это действительно необходимо.
Такая избыточность должна быть использована с умом.
вы это о чем вапще?


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: ssoft от Июнь 26, 2017, 08:11
ИМХО 2-й пример добавляет работы процессору и его надо использовать там, где это действительно необходимо.
Такая избыточность должна быть использована с умом.

ИМХО) это заблуждение. Что raw указатель, что unique_ptr работают одинаково быстро. Вся "избыточность" исчезает на этапе компиляции.


Название: Re: c++ 11/14 vs "старый c++"
Отправлено: Авварон от Июнь 26, 2017, 09:50

ИМХО) это заблуждение. Что raw указатель, что unique_ptr работают одинаково быстро. Вся "избыточность" исчезает на этапе компиляции.

Нет, там чуть больше инструкций. Кто-то из кутешников выкладывал куда-то (возможно, в рассылку) дизассемблированный код.
Из-за обработки исключений, нужно корректно сворачивать стек.
Но я на самом деле разочарую - это экономия на спичках; аналогичный код вставляется при использовании любого не-POD типа (ну представьте, есть 2 строки в классе, первая сконструирвалась, а вторая тровнула. Первую надо удалить. И так на каждый мембер)