Здравствуйте, Аноним, Вы писали:
А>Хочу использовать реализации интерфейсов без динамической реаллокации объектов реализующих их, А>способ примерно такой:
Это стандартная фича языка. Поэтому хаком это является в том случае если этот момент у тебя не задокументирован должным образом.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, Аноним, Вы писали:
А>>Хочу использовать реализации интерфейсов без динамической реаллокации объектов реализующих их, А>>способ примерно такой:
CS>Это стандартная фича языка.
да?? а ссылочку на section в стандарте можно в студию?? %)
CS>Поэтому хаком это является в том случае если этот момент у тебя не задокументирован должным образом.
это хак в любом случае, в зависимости от того документированный он или нет можно только подставлять разные эпитеты... типа "грязный хак", например
ради чего делать себе жизнь сложнее и тем кому неповезет сопровождать этот код, когда можно легко обойтись "стандартным" (Behaviour) паттерном?
сложнее в том плане, что нужно очень аккуратно контролировать размер объектов, типы полей, заботиться о правильной переинициализации, аккуратно писать конструкторы внутренних классов, и все такое прочее... все это очень жестко завязано на конкрентую задачу и layout классов изменяющих поведение, и шаг вправо\лево -- расстрел памяти... ради чего? какой profit??
Здравствуйте, Аноним, Вы писали:
А>Хочу использовать реализации интерфейсов без динамической реаллокации объектов реализующих их, А>...
ужос.
Нафига вообще менять VPTR??
Здесь же просится паттерн стратегия:
// класс у которого хочется круто менять поведениеclass YourFlexibleObject {
private:
Strategy * strategy_;
public:
// вот этот метод меняет стратегиюvoid setStrategy(Strategy * strategy) { this->strategy_ = strategy; }
// интерфейсная часть, которую хочется менять:int getSmth(Arg1 arg1, Arg2 arg2) {
ASSERT_VALID(strategy_);
return strategy_->getSmth(this, arg1, arg2);
}
void doSmth(Arg3 arg3, Arg4 arg4) {
ASSERT_VALID(strategy_);
return strategy_->getSmth(this, arg3, arg4);
}
// ...
};
Strategy — интерфейс, который реализуют нужные тебе конкретные воплощения стратегии.
Эти экземпляры можно выделить один раз и переиспользовать без реаллокации — voila!
Здравствуйте, Аноним, Вы писали:
А>Хочу использовать реализации интерфейсов без динамической реаллокации объектов реализующих их, А>способ примерно такой:
А>class User { // потребитель А>public: А> Interface intf; А> template <class T> changeIntfRealization() { А> // возможные проверки на происхождение T от Interface на манер: static_assert(is_base_of<Interface, T>::value, "Ouch"); А> new (&intf)T(); // происходит подмена VPTR А> } А>};
А>Собственно вопрос в топике.
UB. Вообще, хотя бы деструктор предыдущей реализации надо вызвать перед placement new, ну и позаботиться о том, чтобы хватило памяти (sizeof(intf) >= sizeof любой из реализаций) под все реализации. И это все равно не гарантирует отсутствия проблем при оптимизации.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Тот кто сидит в пруду, Вы писали:
ТКС>Здравствуйте, Аноним, Вы писали:
ТКС>UB. Вообще, хотя бы деструктор предыдущей реализации надо вызвать перед placement new, ну и позаботиться о том, чтобы хватило памяти (sizeof(intf) >= sizeof любой из реализаций) под все реализации. И это все равно не гарантирует отсутствия проблем при оптимизации.
Деструктор, если он тривиальный, вызывать необязательно, UB будет только если размеры или выравние создаваемых объектов не соответсвуют используемой памяти.
Здравствуйте, zaufi, Вы писали:
Z>Здравствуйте, c-smile, Вы писали:
CS>>Здравствуйте, Аноним, Вы писали:
А>>>Хочу использовать реализации интерфейсов без динамической реаллокации объектов реализующих их, А>>>способ примерно такой:
CS>>Это стандартная фича языка. Z>да?? а ссылочку на section в стандарте можно в студию?? %)
3.8 Object lifetime. Единственная, трудность может быть с обеспечением правильного выравнивания, но, если размеры объектов совпадают и память выделяется динамически, корректность гарантируется стандартом.
CS>>Поэтому хаком это является в том случае если этот момент у тебя не задокументирован должным образом.
Z>это хак в любом случае, в зависимости от того документированный он или нет можно только подставлять разные эпитеты... типа "грязный хак", например Z>ради чего делать себе жизнь сложнее и тем кому неповезет сопровождать этот код, когда можно легко обойтись "стандартным" (Behaviour) паттерном? Z>сложнее в том плане, что нужно очень аккуратно контролировать размер объектов, типы полей, заботиться о правильной переинициализации, аккуратно писать конструкторы внутренних классов, и все такое прочее... все это очень жестко завязано на конкрентую задачу и layout классов изменяющих поведение, и шаг вправо\лево -- расстрел памяти... ради чего? какой profit??
Здравствуйте, k.o., Вы писали:
ТКС>>UB. Вообще, хотя бы деструктор предыдущей реализации надо вызвать перед placement new, ну и позаботиться о том, чтобы хватило памяти (sizeof(intf) >= sizeof любой из реализаций) под все реализации. И это все равно не гарантирует отсутствия проблем при оптимизации.
KO>Деструктор, если он тривиальный, вызывать необязательно
Так вроде никто тривиальных деструкторов не обещал
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Тот кто сидит в пруду, Вы писали:
ТКС>Здравствуйте, k.o., Вы писали:
ТКС>>>UB. Вообще, хотя бы деструктор предыдущей реализации надо вызвать перед placement new, ну и позаботиться о том, чтобы хватило памяти (sizeof(intf) >= sizeof любой из реализаций) под все реализации. И это все равно не гарантирует отсутствия проблем при оптимизации.
KO>>Деструктор, если он тривиальный, вызывать необязательно
ТКС>Так вроде никто тривиальных деструкторов не обещал
В исходном сообщении они тривиальные. А если деструктор сам не вызывается, то можно и на не-тривиальные забивать, если, конечно, не нужно то, что они делают.
Здравствуйте, A13x, Вы писали:
А>>Хочу использовать реализации интерфейсов без динамической реаллокации объектов реализующих их, А>>... A>ужос. A>Нафига вообще менять VPTR?? A>Здесь же просится паттерн стратегия:
Что-то ваш паттерн стратегия напоминает паттерн Pimpl
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
KO>Минус за то, что этот код не отвечает на вопрос ТС о грязности хака и не решает проблему смены реализации без переаллокации.
А где вы тут видите "переаллокацию" при смене реализации? При смене там тока std::swap вызывается, который ниче не "переаллоцирует"
А на вопрос о "грязности" тут все ответили — добавлять особо нечего, а энтропию плодить, пересказывая уже сказанное — не хочу.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, ononim, Вы писали:
KO>>Минус за то, что этот код не отвечает на вопрос ТС о грязности хака и не решает проблему смены реализации без переаллокации. O>А где вы тут видите "переаллокацию" при смене реализации? При смене там тока std::swap вызывается, который ниче не "переаллоцирует"
Ну, хорошо, ты решил проблему переаллокации, заранее выделив память для всех используемых реализаций. Ты действительно считаешь это хорошим решением? Кстати, интересно было бы увидеть как это будет выглядеть не для 2-х реализаций, а, хотя бы для 10.
KO>>>Минус за то, что этот код не отвечает на вопрос ТС о грязности хака и не решает проблему смены реализации без переаллокации. O>>А где вы тут видите "переаллокацию" при смене реализации? При смене там тока std::swap вызывается, который ниче не "переаллоцирует" KO>Ну, хорошо, ты решил проблему переаллокации, заранее выделив память для всех используемых реализаций. Ты действительно считаешь это хорошим решением? Кстати, интересно было бы увидеть как это будет выглядеть не для 2-х реализаций, а, хотя бы для 10.
Ну так а давайте писать код согласно требованиям, а не фантазиям. ТС хотел отсутствие реаллокации при смене реализации — он его получил. Если хочется минимизировать размер занятой памяти, — это уже совершенно иное требование, и решение будет тоже иное. К примеру, такое:
class Interface
{
public:
virtual void foo() = 0;
virtual ~Interface() = 0 {};
};
class InterfaceImpl1 : public Interface
{
public:
virtual void foo()
{
printf("InterfaceImpl1 this=0x%x\n", this);
}
};
class InterfaceImpl2 : public Interface
{
public:
virtual void foo()
{
printf("InterfaceImpl2 this=0x%x\n", this);
}
};
class Yanus
{
void *p;
Interface *i;
size_t l;
public:
Yanus(size_t prealloc_size = 0)
:p(0), i(0), l(0)
{
if (prealloc_size)
{
p = malloc(prealloc_size);
if (p) l = prealloc_size;
}
}
~Yanus()
{
if (i)i->~Interface();
}
Interface *operator->() { return i; }
const Interface *operator->() const { return i; }
template<class IFIMPL>
void ChangeFace() throw(std::bad_alloc)
{
if (i)
{
i->~Interface();
i = 0;
}
if (sizeof(IFIMPL)>l)
{
p = realloc(p, sizeof(IFIMPL));
if (!p)
{
l = 0;
throw std::bad_alloc();
}
l = sizeof(IFIMPL);
}
i = new (p) IFIMPL ();
}
};
void test_yanus()
{
Yanus y;
y.ChangeFace<InterfaceImpl1>();
y->foo();
y.ChangeFace<InterfaceImpl2>();
y->foo();
}
ну или хотябы такое:
template <class IMPL1, class IMPL2>
class Yanus
{
char buf[max(sizeof(IMPL1), sizeof(IMPL2))];
Interface *i;
public:
Yanus() : i(0)
{
}
~Yanus()
{
if (i)i->~Interface();
}
Interface *operator->() { return i; }
const Interface *operator->() const { return i; }
void ChangeFace(bool second)
{
if (i)
{
i->~Interface();
i = 0;
}
i = second ?
(Interface *)new (&buf[0]) IMPL1 ()
: (Interface *)new (&buf[0]) IMPL2 ();
}
};
Как много веселых ребят, и все делают велосипед...
Здравствуйте, zaufi, Вы писали:
Z>Здравствуйте, c-smile, Вы писали:
CS>>Здравствуйте, Аноним, Вы писали:
А>>>Хочу использовать реализации интерфейсов без динамической реаллокации объектов реализующих их, А>>>способ примерно такой:
CS>>Это стандартная фича языка. Z>да?? а ссылочку на section в стандарте можно в студию?? %)
А "ссылочку" на что собственно?
На то как работает placement new? Или на то что в C++ нет implicit инициализаций полей структур и классов как в Java например.
Это все имхо учебников начального уровня требует ибо основы.
CS>>Поэтому хаком это является в том случае если этот момент у тебя не задокументирован должным образом.
Z>это хак в любом случае, в зависимости от того документированный он или нет можно только подставлять разные эпитеты... типа "грязный хак", например
Я знаю use cases где это решение приносит значительный профит.
Z>ради чего делать себе жизнь сложнее и тем кому неповезет сопровождать этот код, когда можно легко обойтись "стандартным" (Behaviour) паттерном?
Что есть такое "стандартный (Behaviour) паттерн" в данном контексте?
Z>сложнее в том плане, что нужно очень аккуратно контролировать размер объектов, типы полей, заботиться о правильной переинициализации, аккуратно писать конструкторы внутренних классов, и все такое прочее... все это очень жестко завязано на конкрентую задачу и layout классов изменяющих поведение, и шаг вправо\лево -- расстрел памяти... ради чего? какой profit??
Детский сад право слово. Не ходите дети в лес — там волки.
Еще раз: есть области где именно аккуратное и эффективное прописывание всего и вся есть mission critical.
Я подозреваю что для C++ uses cases это как раз типично. Иначе рекомендовано использовать Java и .NET. Там низкий порог вхождения.
Здравствуйте, ononim, Вы писали: KO>>>>Минус за то, что этот код не отвечает на вопрос ТС о грязности хака и не решает проблему смены реализации без переаллокации. O>>>А где вы тут видите "переаллокацию" при смене реализации? При смене там тока std::swap вызывается, который ниче не "переаллоцирует" KO>>Ну, хорошо, ты решил проблему переаллокации, заранее выделив память для всех используемых реализаций. Ты действительно считаешь это хорошим решением? Кстати, интересно было бы увидеть как это будет выглядеть не для 2-х реализаций, а, хотя бы для 10. O>Ну так а давайте писать код согласно требованиям, а не фантазиям. ТС хотел отсутствие реаллокации при смене реализации — он его получил. Если хочется минимизировать размер занятой памяти, — это уже совершенно иное требование, и решение будет тоже иное. К примеру, такое:
Ещё, код (точнее идея) продемонстрированный ТС позволял использовть произвольное количество реализаций интерфейса. Применяя твой подход, получим что для этого нужно всего лишь бесконечное количество памяти, а так, конечно, никаких переаллокаций, всё согласно требованиям.
Здравствуйте, c-smile, Вы писали:
Z>>это хак в любом случае, в зависимости от того документированный он или нет можно только подставлять разные эпитеты... типа "грязный хак", например CS>Я знаю use cases где это решение приносит значительный профит.
Поподробнее не расскажешь?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Аноним, Вы писали:
А>Хочу использовать реализации интерфейсов без динамической реаллокации объектов реализующих их,
А>Собственно вопрос в топике.
class Interface {
public:
virtual void someFun() =0;
virtual ~Interface(){}
};
class Derived1: public Interface {
public:
void someFun() {
//реализация...
}
};
class Derived2: public Interface {
public:
void someFun() {
//реализация...
}
};
class User { // потребительpublic:
char buff[sizeof(Interface)]; // at least sizeof(Interface)
Interface *intf;
User() : intf(0){
}
~User(){
Release();
}
template <class T>
void changeIntfRealization() {
static_assert(size_of(T) <= size_of(buff), "Ouch");
Release();
intf = new (&buff) T();
}
private:
void Release() {
if (intf) intf->~Interface();
intf = 0;
}
};
int main() {
User user;
if (!user.intf)
cout << "not initialized yet!" << endl;
user.changeIntfRealization<Derived1> ();
user.intf->someFun(); // вызовется реализация Derived1
user.changeIntfRealization<Derived2> ();
user.intf->someFun(); // вызовется реализация Derived2
}
Здравствуйте, c-smile, Вы писали:
CS>>>Это стандартная фича языка. Z>>да?? а ссылочку на section в стандарте можно в студию?? %)
CS>А "ссылочку" на что собственно?
На то, что реализация обязана использовать таблицу виртуальных методов. Откуда это следует?
А если нет , то тогда откуда следует, что можно безопасно размещать один объект по/в памяти другого объекта?
ЗЫ Приведённый в первом сообщении пример не скомпилируется.