Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Приведение shared_ptr от базового типа к производному и обратно / 24 сообщений из 24, страница 1 из 1
16.04.2018, 17:47
    #39631015
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Есть такой код:
Код: 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.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
class B{
public:
int Brightness;
B(): Brightness(100);
};

class D: public B{
public:
int Contrast;
D():
Contrast(200),
B();
};

class С: public B{
public:
int Tone;
C():
Tone(300),
B();
};

void AddTone(std::shared_ptr<C> IndividualSettings)
{
IndividualSettings.Tone++;
}

void AddContrast(std::shared_ptr<D> IndividualSettings)
{
IndividualSettings.Contrast++;
}

void AddBrightness(std::shared_ptr<B> AllSettings, bool UseContrast)
{
AllSettings.Brightness++;

if(UseContrast) AddContrast(AllSettings);//???
else AddTone(AllSettings);//???
}

void main()
{
std::shared_ptr<D> IndividualSettings(std::make_shared<D>);
AddBrightness(IndividualSettings, true); //???
}



Как теперь в вызываемой функции AddBrightness принять значение на базовый класс (потому что это универсальная функция для всех видов настроек)? И как сделать обратное преобразование?
...
Рейтинг: 0 / 0
16.04.2018, 17:59
    #39631023
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
AlekseySQLКак теперь в вызываемой функции AddBrightness принять значение на базовый класс (потому
что это универсальная функция для всех видов настроек)?

Измени параметр функции на "B& AllSettings". И избавься от привычки передавать классы по
значению, там лежат укороченные грабли.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
17.04.2018, 05:06
    #39631253
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
AllSettings.get() вернёт указатель на объект класса шаблонного параметра, его можно (пытаться) кастовать
...
Рейтинг: 0 / 0
17.04.2018, 06:40
    #39631264
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
CEMbAllSettings.get() вернёт указатель на объект класса шаблонного параметра, его можно (пытаться) кастовать

Так 100% заработаю ошибку: shared_ptr можно создавать только от new T или на основе другого shared_ptr. Иначе два умных указателя попробуют удалить один и тот же объект: в твоем решении создается два независимых блока подсчета ссылок на объект.
...
Рейтинг: 0 / 0
17.04.2018, 06:49
    #39631266
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Dimitry SibiryakovИзмени параметр функции на "B& AllSettings". И избавься от привычки передавать классы по
значению, там лежат укороченные грабли.


Так что ли?

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
void AddBrightness(B& AllSettings, bool UseContrast)
{
AllSettings.Brightness++;

if(UseContrast) AddContrast(AllSettings);//???
else AddTone(AllSettings);//???
}

void main()
{
std::shared_ptr<D> IndividualSettings(std::make_shared<D>);
AddBrightness(IndividualSettings, true); //???
}



Почему- то мне кажется, что 100% не взлетит.
...
Рейтинг: 0 / 0
17.04.2018, 06:56
    #39631267
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
AlekseySQLshared_ptr можно создавать только от new Tможно, но лучше создавать через make_shared. Раз уж такая тема, то если тебе вдруг понадобилось снять shared_ptr с this, то для этого есть enable_shared_from_this и shared_from_this

AlekseySQLв твоем решении создается два независимых блока подсчета ссылок на объект.в моём решении один shared_ptr, который ты передаёшь в функцию(это у тебя при передаче создаётся второй shared_ptr, и даже иногда именно так и надо делать, но тут не тот случай), а get() - возвращает указатель на объект типа, заданного в шаблоне , а не shared_ptr.
...
Рейтинг: 0 / 0
17.04.2018, 07:11
    #39631270
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
CEMbAlekseySQLв твоем решении создается два независимых блока подсчета ссылок на объект.в моём решении один shared_ptr, который ты передаёшь в функцию(это у тебя при передаче создаётся второй shared_ptr, и даже иногда именно так и надо делать, но тут не тот случай), а get() - возвращает указатель на объект типа, заданного в шаблоне , а не shared_ptr.

Согласен, что у меня нету ссылки в принимающей функции, и это мой косяк. Но и в твоем решении все также плохо: shared_ptr используют чтобы не следить за временем жизни объекта, чтобы он сам помер когда пропадет в нем необходимость. Если же я получаю сырой указатель (и не имею возможности на его основе создать новый shared_ptr), то все эти плюшки теряются, и я опять должен руками в коде разруливать время жизни объекта. В случае асинхронности (а это мой случай!) решение становится 100% не правильным.
...
Рейтинг: 0 / 0
17.04.2018, 07:26
    #39631271
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Всем спасибо, нашел нужные функции преобразования.

Ответ тут .
...
Рейтинг: 0 / 0
17.04.2018, 08:54
    #39631291
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Прочитал эту статейку . Там комментаторы сходятся на мысли, что делать указатели на базовый класс для производных объектов при отсутствии виртуальных методов не имеет смысла:
Код: plaintext
1.
2.
3.
4.
5.
class Base {};
class Derived : public Base {};

Base* p = new Derived; // в этом нет никакого смысла
delete p; // так, соответственно, тоже никто делать не будет => виртуальный деструктор не нужен



Но почему? В моем примере есть универсальные настройки (базовый класс) и частные настройки (производные классы). Функции работы с универсальными настройками, принимают указатели на базовый класс. При этом никаких виртуальных функций не используется...

Может у меня говно- style?
...
Рейтинг: 0 / 0
17.04.2018, 09:57
    #39631335
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
AlekseySQLНо и в твоем решении все также плохоВ моём решении всё отлично. Ещё раз: я не создаю второй shared_ptr . У тебя в функциях работа с членами-переменными классов A, B и C, вот get() даёт указатель на эти классы, а не новый shared_ptr.
AlekseySQLНо почему?у меня в соседней ветке есть предложение: сделать вывод тестовых сообщений в ctor и dtor и посмотреть самому, что будет.
...
Рейтинг: 0 / 0
17.04.2018, 09:58
    #39631336
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Если я правильно понимаю ваши терзания, то удаление объекта производного класса через указатель на базовый - неопределённое поведение.
Определённость требует наличия виртуальных функций.
Если в классе нет нужды в виртуальных функциях - объявляется виртуальный деструктор.
...
Рейтинг: 0 / 0
17.04.2018, 10:14
    #39631351
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
CEMbЕщё раз: я не создаю второй shared_ptr .

А надо.
...
Рейтинг: 0 / 0
17.04.2018, 10:16
    #39631353
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Basil A. SidorovЕсли я правильно понимаю ваши терзания, то удаление объекта производного класса через указатель на базовый - неопределённое поведение.
Определённость требует наличия виртуальных функций.
Если в классе нет нужды в виртуальных функциях - объявляется виртуальный деструктор.

Насколько я понял деструктор не просто "отдувается" из- за необходимости кому- то в классе быть виртуальным, он ОБЯЗАН быть виртуальным, чтобы объекты можно было удалять с помощью указателя на базовый класс.
...
Рейтинг: 0 / 0
17.04.2018, 13:14
    #39631532
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Как теперь в вызываемой функции AddBrightness принять значение на базовый класс (потому что это универсальная функция для всех видов настроек)? И как сделать обратное преобразование?[/quot]

dynamic_cast
...
Рейтинг: 0 / 0
17.04.2018, 13:17
    #39631537
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Basil A. SidorovЕсли я правильно понимаю ваши терзания, то удаление объекта производного класса через указатель на базовый - неопределённое поведение.
Определённость требует наличия виртуальных функций.
Если в классе нет нужды в виртуальных функциях - объявляется виртуальный деструктор.

Ты опять всё перепутал?

удаление объекта производного класса через указатель на базовый неопределённое поведение, если деструктор базового класса невиртуальный.
...
Рейтинг: 0 / 0
17.04.2018, 13:17
    #39631540
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
AlekseySQLBasil A. SidorovЕсли я правильно понимаю ваши терзания, то удаление объекта производного класса через указатель на базовый - неопределённое поведение.
Определённость требует наличия виртуальных функций.
Если в классе нет нужды в виртуальных функциях - объявляется виртуальный деструктор.

Насколько я понял деструктор не просто "отдувается" из- за необходимости кому- то в классе быть виртуальным, он ОБЯЗАН быть виртуальным, чтобы объекты можно было удалять с помощью указателя на базовый класс.

Правильно понимаешь.
...
Рейтинг: 0 / 0
17.04.2018, 13:24
    #39631555
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Если речь идет про shared_ptr, то преобразование от shared_ptr<Derived> к shared_ptr<Base> происходит автоматически, так же как и Derived* к Base*.
А обратное преобразование происходит с помощью std::dynamic_pointer_cast
Код: plaintext
1.
2.
3.
4.
std::shared_ptr<Base> b;
std::shared_ptr<Derived> d;
b = d;
d = std::dynamic_pointer_cast<Derived>(b);



Ну и с простыми указателями
Код: plaintext
1.
2.
3.
4.
Base* b;
Derived* d;
b = d;
d = dynamic_cast<Derived*>(b);
...
Рейтинг: 0 / 0
17.04.2018, 13:42
    #39631580
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
AlekseySQLА надо.Ну, сам себе проблему придумал, сам решил, молодец
...
Рейтинг: 0 / 0
17.04.2018, 20:36
    #39632044
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
CEMbAlekseySQLА надо.Ну, сам себе проблему придумал, сам решил, молодец


Shared_ptr создают, чтобы осуществлять совместное владение объектом. Поэтому пользоваться сырым указателем очень опасно: в любой момент объект может уничтожиться, потому что сырой указатель "не застолбил" за собой ссылку. Именно поэтому weak_ptr при проверке преобразуется к shared_ptr, чтобы дальше можно было безопасно работать с объектом.
...
Рейтинг: 0 / 0
17.04.2018, 21:22
    #39632061
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
AlekseySQLShared_ptr создают, чтобы осуществлять совместное владение объектом...

....разными потоками. Накрайняк - разными объектами с непредсказуемым временем жизни. У
тебя не наблюдается ни того ни другого.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
18.04.2018, 05:07
    #39632143
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
AlekseySQLв любой момент объект может уничтожитьсяесли у тебя потоки, можно использовать std::atomic или std::mutex. У тебя в коде просто одна итерация. Если ты передаёшь в функцию shared_ptr, то будет сделана копия, счётчик увеличится, и пока ты не покинешь функцию, твой объект не будет уничтожен точно. Поэтому внутри функции нет надобности делать каст с самого shared_ptr, достаточно снять с него указатель на объект класса и работать уже с ним.

Но мне было бы интересно увидеть пример, где необходим каст именно shared_ptr. Раз их сделали, значит они для чего-то понадобились.
...
Рейтинг: 0 / 0
18.04.2018, 08:09
    #39632166
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
Dimitry Sibiryakov....разными потоками. Накрайняк - разными объектами с непредсказуемым временем жизни. У
тебя не наблюдается ни того ни другого.


Ну очевидно, же что в топике приведен всего- навсего пример :)
...
Рейтинг: 0 / 0
18.04.2018, 08:37
    #39632169
AlekseySQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
CEMbЕсли ты передаёшь в функцию shared_ptr, то будет сделана копия, счётчик увеличится, и пока ты не покинешь функцию, твой объект не будет уничтожен точно. Поэтому внутри функции нет надобности делать каст с самого shared_ptr, достаточно снять с него указатель на объект класса и работать уже с ним.

Все верно, но при таком подходе надо соблюдать кучу "но", про которые всегда надо помнить:
1. Передавать shared_ptr по значению.
2. После получения сырого указателя не использовать асинхронность.
3. Помнить какой тип производного класса принимает функция (а их может быть много).
4. Не удалять руками shared_ptr (потому что вроде как больше не нужен).
...
Рейтинг: 0 / 0
18.04.2018, 09:19
    #39632175
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Приведение shared_ptr от базового типа к производному и обратно
AlekseySQL2. После получения сырого указателя не использовать асинхронность.если у тебя есть асинхронные обработки данных, нужно просто правильно их описать или правильно обложить функциями доступа. Иначе есть шанс, что где-нибудь забудешь. Даже если ты сделаешь копию с shared_ptr, данные у тебя могут поменяться, shared_ptr тут проблему асинхронности не решает. И, насколько я понимаю, shared cast тоже не спасёт тебя, если ты принимаешь в функцию ссылку на shared_ptr - его в другом потоке могут убить. Если ты присваивание (к shared_ptr) после каста делаешь - тогда да. Если после каста обращаешься к инкременту - нет.

AlekseySQL3. Помнить какой тип производного класса принимает функция (а их может быть много).в параметрах функции тип виден же? Или что-то другое имелось ввиду?

AlekseySQL4. Не удалять руками shared_ptr (потому что вроде как больше не нужен).да его вообще никогда не надо удалять руками. Даже сбрасывать его требуется крайне редко.

Btw, я когда пишу функцию, я всегда продумываю, что я туда передаю (объект, ссылку, указатель, const) почему и как я там буду с этим работать. Поэтому для меня, например, не проблема держать в голове все "но" :)
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Приведение shared_ptr от базового типа к производному и обратно / 24 сообщений из 24, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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