Re[14]: давайте ка уже разберемся раз и навсегда!
От: rg45 СССР  
Дата: 06.04.11 04:43
Оценка: +1
Здравствуйте, c-smile, Вы писали:

CS>Давай еще раз посмотрим на это дело:


CS>
CS>   Base* obj = new(memory) Base();
CS>   obj->foo();
CS>   new(memory) Particular();
CS>   obj->foo();
CS>


CS>Какая конкретно строка здесь вызывает сомнения?


Строка, помеченная жирным, согласно 3.8.1 порождает неопределенное поведение. Об уже этом говорил zaufi здесь
Автор: zaufi
Дата: 05.04.11
.

Сделать код well-formed можно, подправив его так:
   Base* obj1 = new(memory) Base();
   obj1->foo();
   Base* obj2 = new(memory) Particular();
   obj2->foo();

Причем, из того, что второй фрагмент well-formed, отнюдь не следует, что первый также well-formed, поскольку никто не гарантирует равенства указателей obj1 и obj2.
--
Справедливость выше закона. А человечность выше справедливости.
Re[15]: давайте ка уже разберемся раз и навсегда!
От: jazzer Россия Skype: enerjazzer
Дата: 06.04.11 04:54
Оценка: 15 (3) +2
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, c-smile, Вы писали:


CS>>Давай еще раз посмотрим на это дело:


CS>>
CS>>   Base* obj = new(memory) Base();
CS>>   obj->foo();
CS>>   new(memory) Particular();
CS>>   obj->foo();
CS>>


CS>>Какая конкретно строка здесь вызывает сомнения?


R>Строка, помеченная жирным, согласно 3.8.1 порождает неопределенное поведение. Об уже этом говорил zaufi здесь
Автор: zaufi
Дата: 05.04.11
.


R>Сделать код well-formed можно, подправив его так:

R>
R>   Base* obj1 = new(memory) Base();
   obj1->>foo();
R>   Base* obj2 = new(memory) Particular();
   obj2->>foo();
R>

R>Причем, из того, что второй фрагмент well-formed, отнюдь не следует, что первый также well-formed, поскольку никто не гарантирует равенства указателей obj1 и obj2.

Тут дело не в численном равенстве указателей, они могут быть равны, дело в типизации, в том, что компилятор знает, что obj указывает на Base, и может этим знанием пользоватсья, потому что не предполагается, что тип вдруг изменится — это против правил статически типизированного С++. Например, он возьмет адрес из указателя на vtbl при первом обращении и закеширует его в регистр и дальше все вызовы направит непосредственно в нее, минуя указатель на vptr в объекте. Соответственно он изменения указателя на vptr попроcту не заметит.
А когда у нас есть obj2, компилятор либо видит, откуда он пришел, и ставит соответствующий тип статически (девиртуализация), либо, если функция подмены скрыта в бибилотеке, он просто относится к нему как к новому указателю и должен честно пойти в объект и взять указатель на vptr оттуда (после чего он имеет полное право опять его закешировать и т.д.)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[15]: давайте ка уже разберемся раз и навсегда!
От: c-smile Канада http://terrainformatica.com
Дата: 06.04.11 04:56
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, c-smile, Вы писали:


CS>>Давай еще раз посмотрим на это дело:


CS>>
CS>>   Base* obj = new(memory) Base();
CS>>   obj->foo();
CS>>   new(memory) Particular();
CS>>   obj->foo();
CS>>


CS>>Какая конкретно строка здесь вызывает сомнения?


R>Строка, помеченная жирным, согласно 3.8.1 порождает неопределенное поведение. Об уже этом говорил zaufi здесь
Автор: zaufi
Дата: 05.04.11
.


Назови причины при которых

void* a = new(memory) Base();
void* b = new(memory) Particular();


может приводить к false этого условия

(void*)a == (void*)b


На самом деле если (void*)a != (void*)b это значит что
sizeof Base != sizeof Particular

я желаю услышать также причины при которых это возможно. Классы я описал выше.
Re[16]: давайте ка уже разберемся раз и навсегда!
От: rg45 СССР  
Дата: 06.04.11 05:00
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Назови причины при которых


CS>
CS>void* a = new(memory) Base();
CS>void* b = new(memory) Particular();
CS>


CS>может приводить к false этого условия


CS>
CS>(void*)a == (void*)b
CS>


Ну, например, разработчики компилятора — приколисты. Но это их право, никаких требований стандарта они при этом не нарушают.
--
Справедливость выше закона. А человечность выше справедливости.
Re[14]: давайте ка уже разберемся раз и навсегда!
От: Erop Россия  
Дата: 06.04.11 05:07
Оценка:
Здравствуйте, c-smile, Вы писали:


CS>Давай еще раз посмотрим на это дело:


CS>
CS>   Base* obj = new(memory) Base;
CS>   obj->foo();
CS>   new(memory) Particular; //!!! 1
CS>   obj->foo();               //!!! 2
CS>


CS>Какая конкретно строка здесь вызывает сомнения?


Конкретно тут 2 помеченные
В //!!! 1 нет гарантий, что размеры объектов совпадают. Если они есть, по покажикто и как гарантирует это. Но это можно заткнуть при помощи static_assert, например...
В //!!! 2 нет гарантий, что значение выражения static_cast<Base*>( new(memory) Particular() ) совпадёт с obj...

Кроме того, мне не нравятся пустые скобки после имён типов в new.
Но сомневался я в другом.

E>>Что-то сильно я сомневаюсь, что можно так вольно обращаться с полями. В конце концов, например, деструктор класса позовёт деструктор поля, а там уже совсем и не то...


CS>На чем основаны твои сомнения?

Тут где-то был примерно такой код:
class struct {
    Base Agg;
    void Ups() {
        new(&agg) Particular;  // IMHO, так точно нехорошо делать...
    }
};

И нехорошо по многим причинам сразу.
Во-первых, компилятор может что-то такое сделать в деструкторе, чего нам не понравится
Во-вторых, в пользовательском коде компилятор может быть уверен, что тип поля это Base, и не станет прибегать к виртуальным вызовам вовсе...

Так что нехорошо это всё. И главное, совершенно не понятно ради чего.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[17]: давайте ка уже разберемся раз и навсегда!
От: c-smile Канада http://terrainformatica.com
Дата: 06.04.11 05:27
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, c-smile, Вы писали:


CS>>Назови причины при которых


CS>>
CS>>void* a = new(memory) Base();
CS>>void* b = new(memory) Particular();
CS>>


CS>>может приводить к false этого условия


CS>>
CS>>(void*)a == (void*)b
CS>>


R>Ну, например, разработчики компилятора — приколисты. Но это их право, никаких требований стандарта они при этом не нарушают.


Иными словами ты утверждаешь что можешь себе представить компилятор делающий следующее:

(void*)(b + 1) != (void*)b + sizeof(*b)


А как же begin() и end() итераторы например?
Re[3]: Да здравствует мирное строительство!!!
От: Erop Россия  
Дата: 06.04.11 05:33
Оценка: +2
Здравствуйте, c-smile, Вы писали:

CS>Хотел бы я посмотреть на компилятор делающий "девиртуализацию" COM или Corba интерфейсов которые есть сугубо abstract classes.

CS>COM и Corba интерфейсы имеют форму понимаемую и C++ и C. Т.е. всегда возможно получить доступ к vtbl полю. Хотя бы зайдя через C.

Ну посмотри на gcc и MSVC, например...

Скажем в коде
struct Base { virtual ostream& F() { return std::cout << "Base"; } };
extern void magic_gop_swap( base* ); // тут может сидеть наш хак...
struct Dir : Base { virtual ostream& F() { return std::cout << "Dir"; } };

void test_it()
{
    Base& b = *new Dir;
    b.F() << std::endl; 
    magic_gop_swap( &b )
    b.F() << std::endl; 
    delete &b;
}
любой из этих компиляторов может, и имеет право, дооптимизироваться до кода эквивалентного такому:
void test_it()
{
    Base& b = *new Dir;
    std::cout << "Dir" << std::endl; 
    magic_gop_swap( &b )
    delete &b;
    std::cout << "Dir" << std::endl; 
}


CS>placement new C++ для замены vtbl это конечно не тот кунштюк который рекомендован для использования детям дошкольного возраста.

CS>Просто надо знать что есть такая фича и она работает by C++ nature. Но использовать надо осознанно и по делу. Как всегда в C++ впрочем.
Есть мнение, что единственным делом, по которому это надо использовать осознанно является диверсия...


CS>На войне как на войне.

Зачем же жить "как на войне"? Может лучше НОРМАЛЬНУЮ архитектуру залудить в программе, чтобы хаки не требовались?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[15]: давайте ка уже разберемся раз и навсегда!
От: Erop Россия  
Дата: 06.04.11 05:35
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Причем, из того, что второй фрагмент well-formed, отнюдь не следует, что первый также well-formed, поскольку никто не гарантирует равенства указателей obj1 и obj2.


К сожалению, даже и при равенстве не будет грантии работоспособности. Только при отключенном/отсутствующем оптимизаторе...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[16]: давайте ка уже разберемся раз и навсегда!
От: Erop Россия  
Дата: 06.04.11 05:42
Оценка:
Здравствуйте, c-smile, Вы писали:


CS>Назови причины при которых


CS>
CS>void* a = new(memory) Base();
CS>void* b = new(memory) Particular();
CS>


CS>может приводить к false этого условия


CS>
CS>(void*)a == (void*)b
CS>


Нам это условие не нужно. Нам нужно равенство указателей на Base...

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

CS>На самом деле если (void*)a != (void*)b это значит что

CS>
CS>sizeof Base != sizeof Particular
CS>


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

CS>я желаю услышать также причины при которых это возможно. Классы я описал выше.

А можно чуть-чуть другие классы? А то классы выше вообще не нужны. Вместо них намного проще юзать указатели на функции...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[18]: давайте ка уже разберемся раз и навсегда!
От: Erop Россия  
Дата: 06.04.11 05:47
Оценка: +2
Здравствуйте, c-smile, Вы писали:

CS>
CS>(void*)(b + 1) != (void*)b + sizeof(*b)
CS>


Во-первых, это всё вообще никак не связано с предыдущим.
Во-вторых, в С++ полимрфных векторов не бывает. Либо виртуализация, либо масив объектов. Сразу и то и то нельзя. Ну в смысле можно, конечно, но ССЗБ.
В частности, операция + для указателя и целого валидна только для указателей ВНУТРЬ ВЕКТОРА. Для указателей на одинокие объекты это UB... Вернее неспецифицированное, как мне кажется...

CS>А как же begin() и end() итераторы например?

А в чём там проблемы?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
й на
Re[5]: А правда, расскажи а?
От: Erop Россия  
Дата: 06.04.11 06:05
Оценка: +2
E>Здравствуйте, c-smile, Вы писали:

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

CS>>Я знаю use cases где это решение приносит значительный профит.

E>Поподробнее не расскажешь?


^^^^^^^^^^^^ SUBJ ^^^^^^^^^^^^
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[16]: давайте ка уже разберемся раз и навсегда!
От: rg45 СССР  
Дата: 06.04.11 06:41
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, rg45, Вы писали:


R>>Причем, из того, что второй фрагмент well-formed, отнюдь не следует, что первый также well-formed, поскольку никто не гарантирует равенства указателей obj1 и obj2.


E>К сожалению, даже и при равенстве не будет грантии работоспособности. Только при отключенном/отсутствующем оптимизаторе...


Это да. Я просто проблему, что называется, "беру по частям".
--
Справедливость выше закона. А человечность выше справедливости.
Re[18]: давайте ка уже разберемся раз и навсегда!
От: rg45 СССР  
Дата: 06.04.11 07:01
Оценка:
Здравствуйте, c-smile, Вы писали:


CS>Иными словами ты утверждаешь что можешь себе представить компилятор делающий следующее:


CS>
CS>(void*)(b + 1) != (void*)b + sizeof(*b)
CS>


Выражение (void*)b + sizeof(*b) не компилируемо, поскольку индексирование доступно только для указателей полных типов.

Чтоб мне не приходилось додумывать, что ты имел ввиду, и во избежание разночтений, лучше подправь выражение, а потом я отвечу.
--
Справедливость выше закона. А человечность выше справедливости.
Re: замена VPTR это "грязный" хак?
От: ononim  
Дата: 06.04.11 07:26
Оценка: +1 -2 :)
Хаком тут является отсутствие вызова деструктора и отсутствие проверки необходимого размера. Все. Для рассказывающих ужастики повторяю: ВСЕ.
ЗЫ зря ты топик назвал 'замена VPTR' — это создает ощущение жуткого батхерта, которое и стараются передать многочисленные ужасающиеся в этом топике. Надо называть вещи своими именами — placement new на своей "куче".
Как много веселых ребят, и все делают велосипед...
Re[2]: замена VPTR это "грязный" хак?
От: Erop Россия  
Дата: 06.04.11 07:41
Оценка:
Здравствуйте, ononim, Вы писали:

O>Хаком тут является отсутствие вызова деструктора и отсутствие проверки необходимого размера. Все.

Это-то, как раз, фигня, потому что легко чинится.
Суть хака в том, что мы используем всё тот же указатель...
И вот это неизлечимо. А без этого хака вообще нет повода для страданий. Можно не страдать со всеми этими тонкостями, а просто иметь пул объектов и брать из пула нужный.
Тем более, что объекты без полей, так что можно иметь по статической копии каждого типа и всё...

Повторяю: ВСЁ



O>ЗЫ зря ты топик назвал 'замена VPTR' — это создает ощущение жуткого батхерта, которое и стараются передать многочисленные ужасающиеся в этом топике. Надо называть вещи своими именами — placement new на своей "куче".
Ой, а разве это "своими именами"? IMHO, в зависимости от версии обсуждаемого кода, надо или "..на чужой куче" или "...в storage другого поля". Только конретно эти стороны этого хака не важны, к сожалению...

O>Для рассказывающих ужастики повторяю: ВСЕ.
А ещё крупнее слабо написать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: замена VPTR это "грязный" хак?
От: rg45 СССР  
Дата: 06.04.11 07:41
Оценка:
Здравствуйте, ononim, Вы писали:

O>Хаком тут является отсутствие вызова деструктора и отсутствие проверки необходимого размера. Все. Для рассказывающих ужастики повторяю: ВСЕ.

O>ЗЫ зря ты топик назвал 'замена VPTR' — это создает ощущение жуткого батхерта, которое и стараются передать многочисленные ужасающиеся в этом топике. Надо называть вещи своими именами — placement new на своей "куче".

+1
Флейм также отчасти спровоцирован тем, что исходный пример содержит ошибку. Участники обсуждения тем или иным образом мысленно исправляют эту ошибку и делают это по-разному. Так возникла дискуссия между мной и k.o. — здесь
Автор: rg45
Дата: 05.04.11
в ходе которой выявилась различная трактовка исходного примера.
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: замена VPTR это "грязный" хак?
От: ononim  
Дата: 06.04.11 07:47
Оценка:
O>>Хаком тут является отсутствие вызова деструктора и отсутствие проверки необходимого размера. Все.
E>Это-то, как раз, фигня, потому что легко чинится.
E>Суть хака в том, что мы используем всё тот же указатель...
И что? Все кучи (включая встроенную студийну) работают на "реюзании указателей". Признакомом убивания объекта для любого супероптимизирующего компилятора должен быть вызов деструктора. Которого действительно в коде топикстартера нету, но это не design flaw.

E>Тем более, что объекты без полей, так что можно иметь по статической копии каждого типа и всё...

E>

Повторяю: ВСЁ



O>>ЗЫ зря ты топик назвал 'замена VPTR' — это создает ощущение жуткого батхерта, которое и стараются передать многочисленные ужасающиеся в этом топике. Надо называть вещи своими именами — placement new на своей "куче".
E>Ой, а разве это "своими именами"? IMHO, в зависимости от версии обсуждаемого кода, надо или "..на чужой куче" или "...в storage другого поля". Только конретно эти стороны этого хака не важны, к сожалению...

Своими. new (p) OBJECT (args) — это Placement new. Фича языка про которую тут писали. Указатель p — это по сути свой буфер, для которого ты ручками (читай — своим аллокатором выделяешь память. Потому по сути то что сделал ТС это именно placement new и свой аллокатор. С двумя багами о которых я выше написал.

O>>Для рассказывающих ужастики повторяю: ВСЕ.

E>А ещё крупнее слабо написать?
Запросто. ВСЕ
Как много веселых ребят, и все делают велосипед...
Re[4]: замена VPTR это "грязный" хак?
От: Erop Россия  
Дата: 06.04.11 08:08
Оценка:
Здравствуйте, ononim, Вы писали:

E>>Суть хака в том, что мы используем всё тот же указатель...

O>И что? Все кучи (включая встроенную студийну) работают на "реюзании указателей".
Беда в том, что они работают не как угодно. а на основании довольно сложных правил, описанных, например, в стандарте С++...

O>Признакомом убивания объекта для любого супероптимизирующего компилятора должен быть вызов деструктора. Которого действительно в коде топикстартера нету, но это не design flaw.

Ну а все девушки должны тебе давать. Беда в том, что они хоть по твоему и должны, но всё же не делают этого...
Да, и кстати, если должны, то ты наверное можешь показать документ, эту обязанность устанавливающий?

O>Своими. new (p) OBJECT (args) — это Placement new. Фича языка про которую тут писали. Указатель p — это по сути свой буфер, для которого ты ручками (читай — своим аллокатором выделяешь память. Потому по сути то что сделал ТС это именно placement new и свой аллокатор. С двумя багами о которых я выше написал.


1) про placement new я и не спорил и не спорю. Просто ... короче писать.
2) Про аллокатор не согласен, но главное тут не в аллокаторе.
3) Суть хака НЕ В ТОМ. Суть вот в чём. Пусть у меня есть какая-то иерархия, из экземпляров её классов собрана какая-то сложная структура данных. Ну, например, дерево, какое-то или окошки GUI'я, например.
И вот я хочу чуть подправить поведение одного из узлов этой иерархии, ничего не пересвязывая и не пересоздавая...
Вот тут на сцену обсуждаемый хак и выходит...


O>>>Для рассказывающих ужастики повторяю: ВСЕ.

E>>А ещё крупнее слабо написать?
O>Запросто. ВСЕ

А У МЕНЯ ДЛИНЬШЕ И ТОЛЩЕ!!!

Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: замена VPTR это "грязный" хак?
От: Erop Россия  
Дата: 06.04.11 08:21
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Флейм также отчасти спровоцирован тем, что исходный пример содержит ошибку. Участники обсуждения тем или иным образом мысленно исправляют эту ошибку и делают это по-разному. Так возникла дискуссия между мной и k.o. — здесь
Автор: rg45
Дата: 05.04.11
в ходе которой выявилась различная трактовка исходного примера.


Прикольно. А какие ещё трактовки есть?
Я так понял ТС, что он хотел бы сохранив старый указатель на базу, заиметь по этому адресу объект с модифицированным поведением. IMHO, это всё там довольно прозрачно восстанавливается.
А если придумать какой-то совсем другой вопрос где тоже есть new размещения, то можно много чего наобсуждать...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[14]: замена VPTR это "грязный" хак?
От: Erop Россия  
Дата: 06.04.11 08:35
Оценка:
Здравствуйте, k.o., Вы писали:

KO>можно черновик C++0x посмотреть, там, это почти не изменилось: здесь, тоже 12.4/4.


Спасибо за идею.
Тут смотри что пишут:

A destructor is trivial if it is neither user-provided nor deleted and if:
— the destructor is not virtual,
— all of the direct base classes of its class have trivial destructors, and
— for all of the non-static data members of its class that are of class type (or array thereof), each such
class has a trivial destructor.
Otherwise, the destructor is non-trivial.

требование снижено до отсутствия виртуальности самого деструктора, по сравнению с тем, что я помню.
Интересно, как оно было раньше?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.