LINUX.ORG.RU

c++. Безопасно ли изменение элементов контейнера set


0

0

Безопасно ли изменение не влияющих на сортировку элементов контейнера set?

Вроде бы ничего срашного, ссылка по теме http://angelikalanger.com/Articles/Cuj/01.SetIterators/SetIterators.html

Небольшой пример по сути вопроса:

class A

class B: Baseclass

С set<A> все отлично работает. При использовании set<Baseclass> и помещении в него элементов класса B - во время исполнения в совершенно непредсказуемых местах вылазят ошибки (в libc).

Компилятор не ругается. Бьюсь целый день, никак не могу понять в чем дело. =( Спасите. :)

anonymous

> При использовании set<Baseclass> и помещении в него элементов класса B - во время исполнения в совершенно непредсказуемых местах вылазят ошибки (в libc).

У тебя B обрезается до Baseclass со всеми последствиями. Если нужно хранить в контейнере потомка базового класса - храни указатель на базовый класс.

execve
()
Ответ на: комментарий от execve

>У тебя B обрезается до Baseclass со всеми последствиями. Если нужно хранить в контейнере потомка базового класса - храни указатель на базовый класс.

Спасибо! Я правда тоже уже, пошел мыться и осознал, в чем был не прав. Все же надо иногда делать паузы, какой раз уже замечаю. :D

Зато gdb подарил мне немного любви; узнал много новного. Думал. (8

anonymous
()
Ответ на: комментарий от Kpoxman

>Такая проблема называется slicing в некоторых источниках.

Ээ.. как бы помягче сказать. Это не проблема. ;)

Вот недосып - это да, проблема. %)

anonymous
()

> При использовании set<Baseclass> и помещении в него элементов класса B

А кто-нибудь может показать, как это делается? Я не представляю себе.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

>А кто-нибудь может показать, как это делается? Я не представляю себе.

А никак! ) Нужно хранить указатели Baseclass*, и, по надобности, преобразовывать их к унаследованому от Baseclass типу с помощью

static_cast<Derivedclass*>(Baseclass_pointer)

anonymous
()
Ответ на: комментарий от anonymous

> static_cast<Derivedclass*>(Baseclass_pointer)

Работать не будет, т.к. компилятор не сможет статически вывести Derivedclass* из Baseclass* в этом случае. Только dynamic_cast или reinterpret_cast (очень осторожно, т.к. не во всех случаях корректно сработает).

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от anonymous

Нет, я тоже думаю, что никак, но у анонимуса-топикстартера ведь как то удалось, пусть даже с багой :) Я кстати придумал - через двойной каст к указателю на void и назад: *(BaseClass*)(void*)&derived, но вряд ли он так сделал :) В "обычных" случаях такого происходить вроде бы не должно.

> и, по надобности, преобразовывать их к унаследованому от Baseclass

Есть мнение, что нужно либо использовать полиморфизм, либо не использовать наследование.

anonymous
()
Ответ на: комментарий от watashiwa_daredeska

>Работать не будет, т.к. компилятор не сможет статически вывести Derivedclass* из Baseclass* в этом случае. Только dynamic_cast или reinterpret_cast (очень осторожно, т.к. не во всех случаях корректно сработает).

Вызывающе неверная информация. Номер страницы с примером у Страусатрупа дать? :D

Могу даже цитатку небольшую: "Оператор static_cast осуществляет преобразование родственных типов, например указателя на один тип к указателю на другой тип из _той же иерарархии классов... ... Оператор reinterpret_cast управляет преобразованиями между несвязанными типами .. "

dynamic_cast нужно использовать в случае полиморфного виртуального базового класса.

anonymous
()
Ответ на: комментарий от anonymous

>удалось, пусть даже с багой

Ну не надо, обижаешь.. %)

>*(BaseClass*)(void*)&derived

Фигасе, какой коряжистый костыль! :D

>Есть мнение, что нужно либо использовать полиморфизм, либо не использовать наследование.

Не соглашусь. _Либо_ между этими понятиями неуместно. )

1. Жесткие требования к производительности.
2. Потребовались бы виртуальные поля (свойства). :D
3. Получится получится медленный мегакостыль. %) Зачем? )

anonymous
()
Ответ на: комментарий от anonymous

Я в ахуе.
>> Есть мнение, что нужно либо использовать полиморфизм, либо не использовать наследование.
> Не соглашусь. _Либо_ между этими понятиями неуместно. )
Что ты хотел этим сказать?

> 1. Жесткие требования к производительности.
А этим?
> 2. Потребовались бы виртуальные поля (свойства). :D
Это просто ставит меня в тупик. Это плюс или минус? И вообще, речь всё ещё про c++?
> 3. Получится получится медленный мегакостыль. %) Зачем? )
Э... "медленный мегакостыль" - это полиморфизм? Что так?

gpg
()
Ответ на: комментарий от Legioner

Под "помещением в него" имелся в виду процесс, а не результат.
Это же очевидно.
Успешного результата таким образом, понятное дело, не добиться.

gpg
()
Ответ на: комментарий от gpg

>Я в ахуе.

Поздравляю.

По оставшимся вопросам:
Я говорил о своей задаче и почему я не могу использовать полиморфизм.

По второму твоему посту.
Не понял, что ты хотел вообще сказать. Мы тут разобрались уже вроде. )

anonymous
()
Ответ на: комментарий от anonymous

Про уместность "либо" опустим, хотя форум русскоязычный.

Попробую расжевать
> Я говорил о своей задаче и почему я не могу использовать полиморфизм.
> 1. Жесткие требования к производительности.
Какая связь между производительностью и полиморфизмом?
> 2. Потребовались бы виртуальные поля (свойства)
Что это за хрень и что с ней за проблемы?
Ну и про мегакостыльность полиморфизма хотелось бы услышать.
Растолкуй, уж будь добр.

> По второму твоему посту.
> Не понял, что ты хотел вообще сказать. Мы тут разобрались уже вроде.
Если ты про мой ответ Легионеру, то что именно тебе в нём непонятно?
И заодно, что значит "Мы тут разобрались уже вроде"? С Легионером? Ты не преувеличиваешь?

gpg
()
Ответ на: комментарий от gpg

>Какая связь между производительностью и полиморфизмом?

Динамический полиморфизм времени выполнения.

>Что это за хрень и что с ней за проблемы?

Пример виртуального поля класса в студию, дружок. ;)

>Ну и про мегакостыльность полиморфизма хотелось бы услышать.

Ну ты прямо тяжелый какой-то. =( Мне нужен доступ к свойствам класса, при использовании полиморфизма под это дело мне пришлось бы писАть методы. Выглядело бы все это хреново, т.к. их много и требуется лишь присвоить значение, а также в виду выше сказаного вообще не имеет смысл городить нечто подобное.

>Если ты про мой ответ Легионеру, то что именно тебе в нём непонятно?

Все.

>И заодно, что значит "Мы тут разобрались уже вроде"? С Легионером? Ты не преувеличиваешь?

Со всеми. В т.ч. и с Легионером, который получил ответ на свой вопрос.

>Это жестоко.

Согласен.

anonymous
()
Ответ на: комментарий от anonymous

> Динамический полиморфизм времени выполнения.
Пожалуйста, пример влияния полиморфизма на производительность, о котором стоило бы говорить всерьёз.

> Пример виртуального поля класса в студию, дружок. ;)
Малыш, ты ничего не напутал? Это с тебя пример. Я такой термин впервые слышу.

> Выглядело бы все это хреново, т.к. их много и требуется лишь присвоить значение
Да, это сильный аргумент. Ты в каком классе, если не секрет?

> в виду выше сказаного вообще не имеет смысл городить нечто подобное
Пока я не вижу в "вышесказанном" никакого смысла.

>> Если ты про мой ответ Легионеру, то что именно тебе в нём непонятно?
> Все.
В общем, обратное и не предусматривалось.

> Со всеми. В т.ч. и с Легионером, который получил ответ на свой вопрос.
1. Он получил дурацкий ответ.
2. Это как-то запрещает мне давать свой ответ?

gpg
()
Ответ на: комментарий от gpg

>Пожалуйста, пример влияния полиморфизма на производительность, о котором стоило бы говорить всерьёз.

Пожалуйста, определение того, что ты понимаешь под "всерьез". ;)

>Я такой термин впервые слышу.

А я тебе о чем?

>Да, это сильный аргумент.

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

На да, полиморфизм - это тру. Вещь в себе. Какие еще страшные слова ты знаешь?

>1. Он получил дурацкий ответ.

В каком месте?

>2. Это как-то запрещает мне давать свой ответ?

Да на здоровье. Посмеемся вместе.

anonymous
()
Ответ на: комментарий от anonymous

>> Пожалуйста, пример влияния полиморфизма на производительность, о котором стоило бы говорить всерьёз.
> Пожалуйста, определение того, что ты понимаешь под "всерьез". ;)
Игра в слова тебя характеризует весьма недвусмысленно. Бери любое по своему вкусу, это не имеет значения.

>> Я такой термин впервые слышу.
> А я тебе о чем?
Пока всё ниочём. Так что же это такое - твои загадочные "виртуальные поля" и чем они тебя так пугают?

[словоблудие поскипано]

>>2. Это как-то запрещает мне давать свой ответ?
> Да на здоровье.
Да, запрещает? Или ты не понял вопроса?
> Посмеемся вместе.
Боюсь тебе не догнать, я уже отсмеялся. Разве что ещё что скажешь.

gpg
()
Ответ на: комментарий от anonymous

> Вызывающе неверная информация. Номер страницы с примером у
> Страусатрупа дать? :D

Отнеси эту макулатуру за авторством дохлого страуса в сортир. Жопу
подтирать. У этого говнюка в книжке описан его собственный C++, во
многих местах с реальностью и здравым смыслом имеющий мало общего.

Ты мне лучше программку приведи, где это работает, а не прикрывайся
авторитетами.

> Оператор static_cast осуществляет преобразование родственных типов,
> например указателя на один тип к указателю на другой тип из _той же
> иерарархии классов... ... Оператор reinterpret_cast управляет
> преобразованиями между несвязанными типами ..

Для static_cast приведено *необходимое_но_не_достаточное* условие. Еще
одним условием является возможность *статически* вывести
преобразование, т.е. еще на этапе компиляции.

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

> dynamic_cast нужно использовать в случае полиморфного виртуального
> базового класса.

Почему обязательно виртуального? Что такое "случай полиморфного
виртуального базового класса"? Нижеприведенный пример работает с
невиртуальными классами и преобразует не базовый в наследника и
базовый во второй базовый.

===== BEGIN =====
#include <iostream>

using namespace std;

struct A
{
    int a;
    A( int _a ) : a(_a) {}
    virtual ~A() {}
    virtual int f() { return a; }
};

struct C
{
    int c;
    C( int _c ) : c(_c) {}
    virtual ~C() {}
    virtual int h() { return c; }
};

struct B : A, C
{
    B( int _a ) : A(_a), C(_a) {}
    virtual int f() { return a+1; }
    int g() { return a; }
};

void printA( A* a )
{
    B* b = reinterpret_cast<B*>(a);
    cout << b->g() << " " << b->f() << endl;
    C* c = dynamic_cast<C*>(a);
    cout << c->h() << endl;
}

int main()
{
    B a(1);
    printA( &a );
    return 0;
}
===== END =====

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от anonymous

Прощай, пустомеля.
Привет виртуальным полям.

gpg
()
Ответ на: комментарий от watashiwa_daredeska

> преобразует не базовый в наследника и базовый во второй базовый

Читать как "преобразует не базовый в наследника, а базовый во второй базовый".

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от watashiwa_daredeska

>> dynamic_cast нужно использовать в случае полиморфного виртуального
>> базового класса.

> Почему обязательно виртуального? Что такое "случай полиморфного
виртуального базового класса"?

В общем случае необходимо наличие vtbl. Полиморфный виртуальный класс - скорее всего плод небрежно прослушанных лекций.
А вот почему тебя оставило равнодушным "нужно использовать"?

В любом случае, если это один и тот же анонимус, можешь начинать собирать свой бисер обратно.

gpg
()
Ответ на: комментарий от watashiwa_daredeska

про касты анонимус правильно сказал.

dynamic_cast у тебя работает потому что A полиморфный тип.

static_cast тут тоже можно использовать:

  5.2.9  Static cast        [expr.static.cast]
8 An  rvalue of type "pointer to cv1 B", where B is a class type, can be                                                       
  converted to an rvalue of type "pointer to cv2 D", where D is a  class                                                       
  derived  (_class.derived_) from B, if a valid standard conversion from                                                       
  "pointer to D" to "pointer to B" exists

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

Тем не менее
Note that static_cast relies on static (compile-time) type information and does not perform any run-time type checking.
This means that if pointer to Base, in fact, not refer to an actual Derived the result of the cast is undefined

gpg
()
Ответ на: комментарий от dilmah

> dynamic_cast у тебя работает потому что A полиморфный тип.

А с полиморфностью (требованием наличия vtbl, и более того -- RTTI), я и не спорил. Однако, у анонимуса присутствовали и другие требования: виртуальный, базовый (непонятно, правда, кто кому базовый).

> static_cast тут тоже можно использовать:

Пример в студию! Нефиг тут софистику со спецификациями разводить.

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от watashiwa_daredeska

> Однако, у анонимуса присутствовали и другие требования: виртуальный, базовый (непонятно, правда, кто кому базовый).
Ты излишне придирчив.
Я вижу непротиворечивое объяснение в своеобразии использования терминологии данного анонимуса.
Очевидно, что виртуальность без наследования представляет из себя полную лингамню. Наследование же подразумевает наличие хоть одного базового класса.
Кстати, в данном контексте виртуальный - синоним полиморфный.

>> static_cast тут тоже можно использовать:
> Пример в студию!
Не горячись, его действительно можно использовать для даункаста.
Разыменование нулевого указателя тоже прекрасно компилируется.
Мало того, даже используется в рабочем коде.
Но если яйца пролезают в миксер, это не значит, что их нужно туда совать.

gpg
()
Ответ на: комментарий от gpg

> Ты излишне придирчив.

Спор идет не о вкусе устриц, коий субъективен, а о вполне формальной вещи.

> Кстати, в данном контексте виртуальный - синоним полиморфный.

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

> Не горячись, его действительно можно использовать для даункаста.

Я знаю и нигде с этим не спорил, но... похоже все забыли исходную задачу: хранение в std::set указателей на BaseClass и преобразование в DerivedClass. В этом случае static downcast не работает.

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от watashiwa_daredeska

Ты прав, косноязычие трудно отличить от некомпетентности.
Большая часть пёрлов явно от непонимания, но сомнительные высказывания я пытаюсь трактовать в пользу говорящего.

> похоже все забыли исходную задачу
Отнюдь. Я до последнего надеялся, что мне откроют тайну полиморфлесс-решения именно этой задачи.
Но... "я её за сиську укусил, а она свистнула и улетела".

> В этом случае static downcast не работает.
Могу предположить платформо- и компиляторозависимое решение.
Не продакшн, естественно.

Имхо, обсуждать тут нечего. Для динамика нужна веская причина, реинтерпрет оправдан только легаси АПИ, конст вообще зло, а с людьми,
использующими статик кроме как для интегральных типов надо серьёзно беседовать (множественное наследование я не рассматриваю).

gpg
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.