Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.62/13: Рейтинг темы: голосов - 13, средняя оценка - 4.62
 Аватар для Babysitter
245 / 139 / 53
Регистрация: 23.11.2015
Сообщений: 394

Декоратор и умный указатель

19.07.2016, 15:26. Показов 2660. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
пускай у нас есть, например, декоратор - для примера возьмем реализацию с википедии, через shared_ptr.
C++
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
32
33
34
35
36
37
38
39
#include <iostream>
#include <memory>
 
class IComponent {
public:
    virtual void operation() = 0;
        virtual ~IComponent(){}
};
 
class Component : public IComponent {
public:
    virtual void operation() {
        std::cout<<"World!"<<std::endl;
    }
};
 
class DecoratorOne : public IComponent {
    std::shared_ptr<IComponent> m_component;
 
public:
    DecoratorOne(IComponent* component): m_component(component) {}
 
    virtual void operation() {
        std::cout << ", ";
        m_component->operation();
    }
};
 
class DecoratorTwo : public IComponent {
    std::shared_ptr<IComponent> m_component;
 
public:
    DecoratorTwo(IComponent* component): m_component(component) {}
 
    virtual void operation() {
        std::cout << "Hello";
        m_component->operation();
    }
};
их клиентский код выглядит очень красиво:
C++
1
2
    DecoratorTwo obj(new DecoratorOne(new Component()));
    obj.operation(); // prints "Hello, World!\n"
но, если мне нужно создать компонент, а потом навешать на него кучу декораторов, то это должно выглядеть как-то так
C++
1
2
3
4
5
    IComponent* c = new Component;
    c = new DecoratorOne(c);
    c = new DecoratorTwo(c);
    c->operation(); // prints "Hello, World!\n"
    delete c;
вроде неплохо, но сырые указатели же нельзя использовать, это ансейф - нужно переписывать.
первый вопрос почему что-то такое не работает?
C++
1
2
3
4
    std::shared_ptr<IComponent> c(new Component);
    c.reset(new DecoratorOne(c.get()));
    c.reset(new DecoratorTwo(c.get()));
    c->operation(); // prints red green world
второй вопрос что делают в таких ситуациях?

я придумал только добавить конструкторы, принимающие shared_ptr.
это, конечно, будет нормально работать, но это как-то странно имхо.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class DecoratorOne : public IComponent {
// ...
    DecoratorOne(std::shared_ptr<IComponent> c) : m_component(c) {}
// ...
};
 
class DecoratorTwo : public IComponent {
// ...
    DecoratorTwo(std::shared_ptr<IComponent> c) : m_component(c) {}
// ...
};
 
int main()
{
    std::shared_ptr<IComponent> c(new Component);
    c.reset(new DecoratorOne(c));
    c.reset(new DecoratorTwo(c));
    c->operation();
 
    return 0;
}
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
19.07.2016, 15:26
Ответы с готовыми решениями:

Умный указатель
Здраствуйте. Есть такое задание Тема: «Работа с указателями. Указатели на функцию.» Цель: создать свой собственный ”умный...

Умный указатель
Не могу понять тему с перегрузкой оператора селектор и найти понятное объяснение этой темы. А так же реализацию умного указателя. ...

Функция, возвращающая умный указатель
Здравствуйте, помогите пожалуйста создать функцию, возвращающую умный указатель. Мой вариант не рабочий: class InterfaceVideo{ public:...

8
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
19.07.2016, 15:55
Цитата Сообщение от Babysitter Посмотреть сообщение
первый вопрос почему что-то такое не работает?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//смарт владеет ресурсом
std::shared_ptr<IComponent> c(new Component);
 
// теперь ресурсом владеют два 
// никак не связанных друг с другом смарта
// это уже приведет с ошгибке
auto* ptr = new DecoratorOne(c.get());
    
// сначала первый смарт грохнет свой текущий ресурс
// что сделает декоратор - неконсистентным
// а затем захватит этот самый неконсистентный ресурс
c.reset(ptr);
 
// итого: c владеет декоратором, 
// который думает, что владееет ресурсом.
// а на самом деле его ресурс уже протух
Цитата Сообщение от Babysitter Посмотреть сообщение
я придумал только добавить конструкторы, принимающие shared_ptr.
это, конечно, будет нормально работать, но это как-то странно имхо.
не будет.
у вас возникнет циклическая зависимость между шаред_птр.
родитель будет держать ребенка,
который будет держать родителя.
в результате получите утечки и невозможность грохнуть данные.
1
 Аватар для Babysitter
245 / 139 / 53
Регистрация: 23.11.2015
Сообщений: 394
20.07.2016, 11:03  [ТС]
забавно, внезапно оказалось, что я вообще неверно понимал принцип работы shared_ptr, и теперь вижу насколько это нелепо. мне думалось, что при каждой инициализации shared_ptr будет проверяться такая магическая глобальная таблица, и если кто-то уже владеет этим указателем, то соответственно use_count увеличится со всеми вытекающими.


GC придумал себе, стыдненько

Добавлено через 1 час 22 минуты
мне все еще не помешала бы помощь. вот так по идее это должно записываться для unique_ptr.
но клиентский код выглядит все равно жутко костыльно, и я не уверен в правильности. как это пишется в реальном мире?

C++
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <memory>
 
class IComponent {
public:
    virtual void operation() = 0;
    virtual ~IComponent(){}
};
 
class Component : public IComponent {
public:
    virtual void operation() {
        std::cout<<"World!"<<std::endl;
    }
};
 
class DecoratorOne : public IComponent {
    std::unique_ptr<IComponent> m_component;
 
public:
    DecoratorOne(IComponent* component): m_component(component) {}
    DecoratorOne(std::unique_ptr<IComponent> component): m_component(std::move(component)) {}
 
    virtual void operation() {
        std::cout << ", ";
        m_component->operation();
    }
};
 
class DecoratorTwo : public IComponent {
    std::unique_ptr<IComponent> m_component;
 
public:
    DecoratorTwo(IComponent* component): m_component(component) {}
    DecoratorTwo(std::unique_ptr<IComponent> component): m_component(std::move(component)) {}
 
    virtual void operation() {
        std::cout << "Hello";
        m_component->operation();
    }
};
 
int main()
{
    std::unique_ptr<IComponent> p(new Component());
    p.reset(new DecoratorOne(std::move(p)));
    p.reset(new DecoratorTwo(std::move(p)));
    p->operation();
    return 0;
}
Добавлено через 17 часов 32 минуты
я так понял, что ответов не будет и даже, как мне кажется, понял почему. я пытаюсь слишком буквально перевести гофовский паттерн на более современный язык. паттерн должен быть изначально написан на этом самом современном языке.

однако вопрос тут очень серьезный - он скрывает мое непонимание в корне как писать код на С++ вообще.

все говорят про абстракции, про то, что программировать нужно на уровне интерфейсов, про то, что сырые указатели - это опасно, про то, что new/delete в клиентском коде не должен существовать, но вот же он, самый что ни на есть классический пример, кусок кода, которому уже непонятно сколько лет, сколько раз он был использован и я просто не могу применить те правила, о которых все столько говорят. а классические фабрики, это же по сути return new Object(); то есть мы возвращаем указатель на выделенную динамическую память - разбирайтесь сами, ловите там на выходе умными указателями или сами руками убивайте.

даже в начале изучения плюсов не чувствовал себя таким новичком.
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
20.07.2016, 12:40
Babysitter, опиши сперва нормальный пример, на котором ты хочешь посмотреть, как пишутся декораторы.
Эти Decorator1, Decorator2... - ну жесть же.
0
 Аватар для Babysitter
245 / 139 / 53
Регистрация: 23.11.2015
Сообщений: 394
20.07.2016, 13:39  [ТС]
ct0r, лол, так нормально? я думал, что прочитать декоратор с википедии должно быть проще, чем выдумывать дурацкие примеры вроде кофе. напиток, от него кофе. декорируем молоком и шоколадом.

C++
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <memory>
 
class Beverage {
public:
    virtual void describe() = 0;
    virtual ~Beverage(){}
};
 
class Espresso : public Beverage {
public:
    virtual void describe() {
        std::cout<<" Fresh Espresso!"<<std::endl;
    }
};
 
class Milk : public Beverage {
    std::unique_ptr<Beverage> m_bev;
 
public:
    Milk(std::unique_ptr<Beverage> Espresso): m_bev(std::move(Espresso)) {}
 
    virtual void describe() {
        std::cout << "Milk + ";
        m_bev->describe();
    }
};
 
class Choc : public Beverage {
    std::unique_ptr<Beverage> m_bev;
 
public:
    Choc(std::unique_ptr<Beverage> Espresso): m_bev(std::move(Espresso)) {}
 
    virtual void describe() {
        std::cout << "Choclate + ";
        m_bev->describe();
    }
};
 
int main()
{
    std::unique_ptr<Beverage> p(new Espresso());
    p.reset(new Milk(std::move(p)));
    p.reset(new Choc(std::move(p)));
    p->describe();
    return 0;
}
Добавлено через 22 минуты
имя параметра в конструкторе - несчастный случай. последствия программирования с помощью замен в текстовом редакторе.
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
20.07.2016, 16:14
Лучший ответ Сообщение было отмечено Babysitter как решение

Решение

Babysitter, то, что ты написал, можно написать так например:
C++
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
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <type_traits>
 
class Beverage {
public:
    virtual void describe() const = 0;
    virtual ~Beverage() {}
};
 
class Espresso: public Beverage {
public:
    void describe() const override {
        std::cout<<" Fresh Espresso!\n";
    }
};
 
template<typename T>
class MilkBeverage: public T {
    static_assert(std::is_base_of<Beverage, T>::value,
                  "Template argument must be a Beverage");
public:
    void describe() const override {
        std::cout << "Milk + ";
        T::describe();
    }
};
 
template<typename T>
class ChocBeverage: public T {
    static_assert(std::is_base_of<Beverage, T>::value,
                  "Template argument must be a Beverage");
public:
    void describe() const override {
        std::cout << "Chocolate + ";
        T::describe();
    }
};
 
int main() {
    ChocBeverage<MilkBeverage<Espresso>> beverage;
    beverage.describe();
}
Добавлено через 6 минут
Или так:
C++
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
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <type_traits>
 
class Beverage {
public:
    virtual void describe() const = 0;
    virtual ~Beverage() {}
};
 
class Espresso: public Beverage {
public:
    void describe() const override {
        std::cout<<" Fresh Espresso!\n";
    }
};
 
class MilkBeverage: public Beverage {
private:
  Beverage& b_;
public:
    explicit MilkBeverage(Beverage& b): b_(b) {}
    void describe() const override {
        std::cout << "Milk + ";
        b_.describe();
    }
};
 
class ChocBeverage: public Beverage {
private:
  Beverage& b_;
public:
    explicit ChocBeverage(Beverage& b): b_(b) {}
    void describe() const override {
        std::cout << "Chocolate + ";
        b_.describe();
    }
};
 
int main() {
    Espresso e;
    MilkBeverage m{ e };
    ChocBeverage c{ m };
    c.describe();
}
Но опять же, это упрощенные версии. В реальном мире все сложнее.
2
8 / 5 / 0
Регистрация: 03.07.2013
Сообщений: 30
07.11.2016, 11:04
Добрый день!
А если понадобится удалить один из декораторов, необходимо удалить весь компонент и заново его сформировать?
0
 Аватар для Babysitter
245 / 139 / 53
Регистрация: 23.11.2015
Сообщений: 394
07.11.2016, 21:48  [ТС]
Цитата Сообщение от Alexorleon Посмотреть сообщение
А если понадобится удалить один из декораторов, необходимо удалить весь компонент и заново его сформировать?
ну так как ссылку нельзя перенаправить на другой объект после создания, а реализация через шаблоны вообще генерирует код компайлтайм, то эти реализации не позволят такое сделать. для классики из гофа, по идее, нужно просто перебить два указателя и готово.
0
 Аватар для Babysitter
245 / 139 / 53
Регистрация: 23.11.2015
Сообщений: 394
28.12.2016, 16:28  [ТС]
пы сы

кстати во втором примере тут расставлены классические грабли
весчь очевидная, но бывает, что не ожидаешь таких проблем и ищешь долго

C++
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <type_traits>
 
class Beverage {
public:
    virtual void describe() const = 0;
    virtual ~Beverage() {}
};
 
class Espresso: public Beverage {
public:
    void describe() const override {
        std::cout<<" Fresh Espresso!\n";
    }
};
 
class MilkBeverage: public Beverage {
private:
  Beverage& b_;
public:
    explicit MilkBeverage(Beverage& b): b_(b) {}
    void describe() const override {
        std::cout << "Milk + ";
        b_.describe();
    }
};
 
class ChocBeverage: public Beverage {
private:
  Beverage& b_;
public:
    explicit ChocBeverage(Beverage& b): b_(b) {}
    void describe() const override {
        std::cout << "Chocolate + ";
        b_.describe();
    }
};
 
int main() {
    Espresso e;
    MilkBeverage m1{ e };
    MilkBeverage m2{ m1 };
    MilkBeverage m3{ m2 };
    m3.describe();
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.12.2016, 16:28
Помогаю со студенческими работами здесь

Умный указатель и динамический массив
Здравствуйте! Есть проблема со следующим заданием. Есть класс умного указателя, используя его необходимо, создать каталог товаров (+ 2...

Умный указатель для класа
Нужно написать клас умный указатель для матрицы чтобы в результате с помощью этого указателя можно было перемещаться по матрице и...

Умный указатель своими руками
Доброго времени суток. Изобразил следующую структуру: имеется класс-контейнер, фактически обертка для одномерного массива. И...

Каст нулевого литерала в умный указатель
читаю я сейчас modern effective c++ и столкнулся с примерно таким листингом void foo(std::shared_ptr&lt;std::string&gt; x) { if...

Умный указатель который представлен в виде шаблонного класса
Я такой создал и мне в нём нужно написать функцию для подсчёта указателей на объект Если честно не представляю даже как можно добиться...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru